Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

State updates in Flutter

Tags:

state

flutter

I'm new to Flutter and I'm having an issue understanding how states work.
I've setup a page in my app as a StatefulWidget and then inside the sate for that page one of the main components is a separate StatefulWidget.

The inner widget shows a question and allows the user to enter an answer.

What I then wanted to do was show the next answer on the same page.

I have my inner widget callback to my page state once the answer has been entered.

I attempted to replace my inner widget with another copy, however the state is not reset. That is a new state is not created and initState() is never called again.

Is there a specific call or method I should be using to achieve this?

Edit: so for example if I had the following

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState(){
     changeContent();
  }

  Widget innerWidget;
  void changeContent(){
     setState((){
        innerWidget = new CustomStatefullWidget();
     }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            innerWidget
          ],
        ),
      ),
    );
  }
}

Here CustomStatefullWidget is a class I've created as a stand alone interactive part of the page. The actual content shouldn't matter for this example.

What I had expected was that whenever changeContent() was called then the innerWidget would have a new state but that isn't the case. The state for that is already stored in the tree and isn't refreshed when a new instance of the widget is created.
How can I force flutter to clear that part of the tree or recognize I want the state reset?

like image 788
peopletookallthegoodnames Avatar asked May 07 '18 04:05

peopletookallthegoodnames


1 Answers

That is the expected behavior. When a parent rebuild flutter compare the new widget tree to the old one.

This way, flutter is able to know which widgets got "updated" and which got added/removed.

For added widgets, it'll create a new state. initState is called. For updated widgets ; flutter will reuse the old widget and call didUpdateWidget by passing as parameter the old "widget" part as parameter. As for removed widget, it'll call dispose.

In your case, you expected that initState would be called once again. But in fact it got "updated".


From this point you have two solutions to reset the state :

Implement a didUpdateWidget. Which would reset your state or do whatever else you want. This is the optimal approach, which you should consider. As you don't necessarily want to reset the children of your "new statefulwidget".

There's also the "lazy" solution, which is to tell flutter "Hey, this is a different widget. don't reuse the old one". That is achieved using Key.

More info in key usage here

That would be as simple as changing your changeContent method to the following:

Widget innerWidget;
void changeContent(){
  setState((){
      innerWidget = new CustomStatefullWidget(key: new UniqueKey());
  }
}
like image 160
Rémi Rousselet Avatar answered Oct 08 '22 09:10

Rémi Rousselet