Flutter - State of widget is not changing

775

Firstly, @Darish is right in that you should probably use another kind of state management system but for the question "How do I refresh the State of the Widget from Child Widget." I'll provide two simple answers:

  1. Move your _handleSubmitted method up to your ChatState widget and pass it through to your ChatWidget:

    class ChatState extends State<ChatScreen> {
    
      ...
      @override
      Widget build(BuildContext context) {
          ...
          Container(
            child: ChatWidget(onMessageSubmitted: this._handleSubmitted)),
          ...
      }
    
      void _handleSubmitted(String text) {
        ChatMessage message = new ChatMessage(
          text: text,
        );
    
        setState(() {
          MyClass.messages.insert(0, message);
        });
      }
    }
    

    Then from your child widget:

    class ChatWidget extends StatefulWidget {
    
      final Function(String) onMessageSubmitted;
    
      ChatWidget({this.onMessageSubmitted});
    
      @override
      ChatWidgetState createState() => ChatWidgetState();
    }
    
    class ChatWidgetState extends State<ChatWidget> {
      ...
    
      Widget _buildTextComposer() {
        ...
        TextField(
          controller: _textController,
          onSubmitted: _handleSubmitted,
          decoration: InputDecoration.collapsed(
          hintText: "Send a message"),
        ),
        ...
        IconButton(
          ...
          onPressed: () {
            _handleSubmitted(_textController.text);
          },
        ),
        ...
      }
    
      void _handleSubmitted(String text) {
        _textController.clear();
    
        widget.onMessageSubmitted(text);
      }
      ...
    }
    
  2. Access your ChatState directly from your ChatWidgetState:

    class ChatScreen extends StatefulWidget {
    
      ...
    
      static ChatState of(BuildContext context) => context.findAncestorStateOfType<ChatState>();
    }
    
    class ChatState extends State<ChatScreen> {
    
      ...
    
      void onMessageSubmitted(String text) {
        ChatMessage message = new ChatMessage(
          text: text,
        );
    
        setState(() {
          MyClass.messages.insert(0, message);
        });
      }
    }
    

    Then in your ChatWidget you can keep as is, but in your ChatWidgetState change your _handleSubmitted method like so:

    void _handleSubmitted(String text) {
      _textController.clear();
    
      ChatScreen.of(context).onMessageSubmitted(text);
    }
    

Number 2 is closer to other arguably better methods of state management, but both are examples of updating the state of a parent widget directly from a child widget.

Share:
775
Shafiul Islam Sajib
Author by

Shafiul Islam Sajib

Updated on December 17, 2022

Comments

  • Shafiul Islam Sajib
    Shafiul Islam Sajib over 1 year

    I am almost new to Flutter and trying to develop a chat application. Whenever the user sends a message it should change the State of the Widget and the message should be displayed in a Listview.

    The case is that the Widget State does not change on Button press. But if I Hot Reload my app it changes the State of the Widget and the message is displayed. I am using two Widgets for the view and the setState() method is called in the Child Widget. How do I refresh the State of the Widget from Child Widget.

    Please review my codes and let me know the solution for it. Thanks in advance.



    Parent Widget:

    class ChatScreen extends StatefulWidget {
    
      @override
      ChatState createState() => ChatState();
    }
    
    class ChatState extends State<ChatScreen> {
    
      static const int _logout = 303;
    
      @override
      Widget build(BuildContext context) {
    
        return Scaffold(
    
          appBar: AppBar(
            title: Text(Strings.appNameString),
            actions: <Widget>[
    
              //IconButton(icon: Icon(Icons.add), onPressed: () {}),
    
              PopupMenuButton<int>(
    
                icon: Icon(Icons.more_vert),
                elevation: 10,
                //padding: EdgeInsets.all(5),
                offset: Offset(0, 100),
                itemBuilder: (BuildContext context) => [
    
                  PopupMenuItem(child: Text("Logout"), value: _logout,),
                  //PopupMenuDivider(height: 5,),
                ],
                onSelected: (value) {
    
                  switch(value) {
    
                    case _logout: {
    
                      MyClass.SignOutofGoogle();
                    } break;
    
                    default: break;
                  }
                },
              ),
            ],
          ),
          body: Column(
    //        crossAxisAlignment: CrossAxisAlignment.center,
    //        mainAxisSize: MainAxisSize.max,
    //        mainAxisAlignment: MainAxisAlignment.end,
    
            children: <Widget>[
    
              Flexible(child: ListView.builder(
                  padding: new EdgeInsets.all(8.0),
                  reverse: true,
                  itemBuilder: (_, int index) => MyClass.messages[index],
                  itemCount: MyClass.messages.length)),
              Container(
                  child: ChatWidget()),
            ],
          ),
        );
      }
    
    }
    



    Child Widget:

    class ChatWidget extends StatefulWidget {
    
      @override
      ChatWidgetState createState() => ChatWidgetState();
    }
    
    class ChatWidgetState extends State<ChatWidget> {
    
      final TextEditingController _textController = new TextEditingController();
    
      Widget _buildTextComposer() {
        return Container(
          margin: const EdgeInsets.symmetric(horizontal: 10.0),
    
          child: Align(
    
            child: Column(
    
              children: <Widget>[
                Divider(height: 5.0, color: Colors.lightBlue,),
                Container(
    
                  height: 6.8 * SizeConfig.heightSizeMultiplier,
                  child: Row(
    
                    children: <Widget>[
                      Container(
                        child: IconButton(
                            icon: Icon(Icons.add_photo_alternate),
                            iconSize: 6.7 * SizeConfig.imageSizeMultiplier,
                            color: Colors.lightBlueAccent,
                            onPressed: () {}),
                      ),
                      Flexible(
                        child: TextField(
                          controller: _textController,
                          onSubmitted: _handleSubmitted,
                          decoration: InputDecoration.collapsed(
                              hintText: "Send a message"),
                        ),
                      ),
                      Container(
                        margin: EdgeInsets.symmetric(horizontal: 4.0),
    
                        child: IconButton(
                            icon: Icon(Icons.send),
                            iconSize: 6.7 * SizeConfig.imageSizeMultiplier,
                            color: Colors.lightBlueAccent,
                            onPressed: () {
                              _handleSubmitted(_textController.text);
                            }),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    
      void _handleSubmitted(String text) {
    
        _textController.clear();
    
        ChatMessage message = new ChatMessage(
          text: text,
        );
    
        setState(() {
          MyClass.messages.insert(0, message);
        });
      }
    
      @override
      Widget build(BuildContext context) {
    
        return _buildTextComposer();
      }
    }
    
    
    class ChatMessage extends StatelessWidget {
    
      final String text;
    
      ChatMessage( {
        this.text
      });
    
      @override
      Widget build(BuildContext context) {
        return new Container(
          margin: const EdgeInsets.symmetric(vertical: 10.0),
    
          child: Row(
            //crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.end,
    
            children: <Widget>[
              Column(
                crossAxisAlignment: CrossAxisAlignment.end,
    
                children: <Widget>[
                  //Text(MyClass.loggeduser.userName, style: Theme.of(context).textTheme.subhead),
                  Text("Sajib", style: Theme.of(context).textTheme.subhead),
                  Container(
                    margin: const EdgeInsets.only(top: 5.0),
                    child: Text(text),
                  ),
                ],
              ),
              Container(
                margin: const EdgeInsets.only(right: 6.0, left: 12.0),
    
                child: CircleAvatar(
                  //backgroundImage: NetworkImage(MyClass.loggeduser.photoUrl)),
                    child: Icon(Icons.account_circle, color: Colors.lightBlueAccent,)),
              ),
            ],
          ),
        );
      }
    }
    
    • Darish
      Darish over 4 years
    • Shafiul Islam Sajib
      Shafiul Islam Sajib over 4 years
      @Darish My case is not the same as in the document suggested by you.
    • Darish
      Darish over 4 years
      The solution you need is some kind of state management set up, and in that document, it clearly explains how to setup one.
    • kuhnroyal
      kuhnroyal over 4 years
      setState only works for the state of this particular Widget. You can not setState and apply changes to MyClass.
    • Shafiul Islam Sajib
      Shafiul Islam Sajib over 4 years
      @kuhnroyal I am trying to setState the state of ChatScreen.
    • kuhnroyal
      kuhnroyal over 4 years
      You are calling setState in ChatWidgetState but it has not state. Your state (messages) is in MyClass. As Darish said, you need some form of state management.
    • Shafiul Islam Sajib
      Shafiul Islam Sajib over 4 years
      @kuhnroyal ok. I will try something based on the documentation. But a proper example would be more helpful for me.
  • Shafiul Islam Sajib
    Shafiul Islam Sajib over 4 years
    Thank you for your explanation and help. I haven't tried your solution yet. I will try it and if it works I will vote this as the correct solution. Thanks a lot again.