I am currently having an issue while fetching a Provider' value in
initstate`.
I want to set a default value in dropdown in an Appbar and other parts in body. But I got an error saying dependOnInheritedElement() was called before initstate() in flutter
.
My full code is below
main.dart
import 'package:test_eoil/model/button_data.dart';
import 'package:test_eoil/model/output_data.dart';
import 'screen/screen.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(providers: [
// ChangeNotifierProvider<ChordData>(create: (context) => ChordData()),
ChangeNotifierProvider<OutputData>(create: (context) => OutputData()),
ChangeNotifierProvider<ButtonData>(create: (context) => ButtonData())
],
child: MaterialApp(
home: Screen(),
),
);
}
}
screen.dart
in screen folder
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_eoil/model/button_data.dart';
import 'package:test_eoil/model/output_data.dart';
class Screen extends StatefulWidget {
@override
_ScreenState createState() => _ScreenState();
}
class _ScreenState extends State<Screen> {
Widget dropdownWidget() {
return DropdownButton<Button>(
items: Provider.of<ButtonData>(context).buttons.map((Button value) {
return new DropdownMenuItem<Button>(
value: value,
child: new Text(value.type.toString()),
);
}).toList(),
onChanged: (Button newValue) {
Provider.of<ButtonData>(context).setSelectedItem(newValue);
},
value: Provider.of<ButtonData>(context).selectedButton,
);
}
@override
void initState() {
Provider.of<ButtonData>(context).selectedButton = Provider.of<ButtonData>(context).buttons.first;
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<OutputData>(
builder: (context, outputData, child) => Scaffold(
appBar: AppBar(
title: Text("${Provider.of<ButtonData>(context).selectedButton}"), // new Text(widget.title), // "${Provider.of<ButtonData>(context).selectedButton.key}"
actions: <Widget>[
dropdownWidget(),
],
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.centerRight,
padding: new EdgeInsets.symmetric(
vertical: 24.0, horizontal: 12.0),
child: outputData.outputs[0].output3.length > 2
? Text(
'${outputData.outputs[0].output3.substring(1, outputData.outputs[0].output3.length-1)}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
))
: Text('${outputData.outputs[0].output3}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
)),
),
Container(
alignment: Alignment.centerRight,
padding: new EdgeInsets.symmetric(
vertical: 24.0, horizontal: 12.0),
child: outputData.outputs[0].output2.length > 2
? Text(
'${outputData.outputs[0].output2.substring(1, outputData.outputs[0].output2.length-1)}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
))
: Text('${outputData.outputs[0].output2}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
)),
),
Container(
alignment: Alignment.centerRight,
padding: new EdgeInsets.symmetric(
vertical: 24.0, horizontal: 12.0),
child: Text('${outputData.outputs[0].output1}', // outputData.outputs[0].output1
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
)),
),
],
),
Expanded(
child: new Divider(),
),
Column(children: [
Row(children: [
buildButton("CLEAR"),
buildButton(""),
buildButton("PLAY"),
// buildButton("/")
]),
])
],
)));
}
Widget buildButton(String buttonText) {
return new Expanded(
child: new OutlineButton(
padding: new EdgeInsets.all(30.0),
child: new Text(
buttonText,
style: TextStyle(fontSize: 20.0),
),
onPressed: () => print("test"),
),
);
}
}
button_data.dart
in model folder
import 'package:flutter/foundation.dart';
//import 'dart:collection';
class Button {
final int id;
final String type;
final String numberone;
final String numbertwo;
final String numberthree;
Button({this.id, this.type, this.numberone, this.numbertwo, this.numberthree});
}
class ButtonData extends ChangeNotifier {
List<Button> _buttons = [
Button(
type: "A",
numberone: "1",
numbertwo: "2",
numberthree: "3",
),
Button(
type: "B",
numberone: "A",
numbertwo: "B",
numberthree: "C",
),
];
List<Button> get buttons => _buttons;
Button _selectedButton;
Button get selectedButton => _selectedButton;
set selectedButton(Button button) {
_selectedButton = button;
notifyListeners();
}
void setSelectedItem(Button s) {
_selectedButton = s;
notifyListeners();
}
Button getKey(String value) {
return _buttons
.where((button) => button.type == value).first;
}
String getNumberOne(String value) {
return _buttons
.where((button) => button.type == value)
.map((button) => (button.numberone))
.toString();
}
String getNumberTwo(String value) {
return _buttons
.where((button) => button.type == value)
.map((button) => (button.numbertwo))
.toString();
}
String getNumberThree(String value) {
return _buttons
.where((button) => button.type == value)
.map((button) => (button.numberthree))
.toString();
}
}
output_data.dart
in model folder
import 'package:flutter/foundation.dart';
class Output {
final int id;
String output1;
String output2;
String output3;
Output({this.id, this.output1, this.output2, this.output3});
}
class OutputData extends ChangeNotifier {
List<Output> _outputs = [
Output(output1: 'Hello', output2: 'Hi', output3: 'Nice'),
Output(output1: 'Haha', output2: 'Bye', output3: 'Sad'),
];
List<Output> get outputs {
return _outputs;
}
}
To be honest, I want to make it work without initstate()
if possible(I heard that provider pattern doesn't need stful)
The reason I come up with an initstate()
is this is the only solution (as much as I know) to set the default value in provider.
Hope you guys help me!
Issue is solved by adding Button_data constructor in button_data.dart
.
ButtonData () {
_selectedButton = _buttons.first;
}
Is initState called before build? initState() This is the first method called when the widget is created (after the class constructor, of course.) initState is called once and only once.
Flutter – initSate() The initState() is a method that is called when an object for your stateful widget is created and inserted inside the widget tree. It is basically the entry point for the Stateful Widgets.
💡 Tip 3: Don't call setState in initState methods initState will trigger a rebuild after completion so it's not necessary to call setState inside this method.
initState In Flutter? initState() is a method that is called once when the Stateful Widget is inserted in the widget tree. We generally override this method if we need to do some sort of initialization work like registering a listener because, unlike build(), this method is called once.
I also mentioned in my previous answer that Provider.of(context)
is supposed to be used inside the widget tree, and anything that is outside of the build()
method, is not in the widget tree. But if you still want to use it, then you need to set the listen
parameter to false
.
Like so:
@override
void initState() {
Provider.of<ButtonData>(context, listen: false).selectedButton = Provider.of<ButtonData>(context, listen: false).buttons.first;
super.initState();
}
But as you mentioned in your question, you don't want to use initState
to set the default value. In every programming language, when you declare a variable with a value, that value becomes it's initial / default value, and you can change it later.
Instead of using initState
, you can edit the following in your ButtonData
class.
//Remove this.
List<Button> get buttons => _buttons;
Button _selectedButton;
Button get selectedButton => _selectedButton;
//Instead, Use this.
List<Button> get buttons => _buttons;
Button _selectedButton = _buttons.first;
Button get selectedButton => _selectedButton;
//This will declare the `selectedButton` variable with a default value.
//Happy coding! :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With