Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dependOnInheritedElement() was called before initstate() in flutter

I am currently having an issue while fetching a Provider' value ininitstate`.

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;
  }
like image 912
Brooklyn Lee Avatar asked Feb 23 '20 15:02

Brooklyn Lee


People also ask

Is initState called before build?

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.

What is initState method in flutter?

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.

Can we call setState in initState?

💡 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.

What is initState and super initState in flutter?

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.


1 Answers

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! :)
like image 125
hysabone.com Avatar answered Nov 09 '22 10:11

hysabone.com