Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

dart - 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;
  }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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! :)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...