setState not reloading state in Dart / Flutter?

2020-04-21 01:35发布

问题:

I followed the Flutter tutorial from Google CodeLabs -

Part 1

Part 2

Then I tried adding SharedPreferences to persist data. Saving data works perfectly but deleting doesn't.

My complete code is available at https://github.com/deadcoder0904/flutter-startup-name-generator/

Screen 1 (Lists all startup names)

Screen 2 (All saved startup names from Screen 1 show here)

On Screen 2, deleting a startup name by clicking on trash icon doesn't remove the data instantly. I have to traverse to Screen 1 & back again at Screen 2 to see the item being removed.

The error is in setState below or you can also view it on Github with nice formatting

void _pushSaved() {
    Navigator.of(context).push(
        MaterialPageRoute<void>(
            builder: (BuildContext context) {
                final Iterable<ListTile> tiles = _saved.map(
                    (String word) {
                        return ListTile(
                            title: Row(
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                children: <Widget>[
                                    Text(
                                        word,
                                        style: _biggerFont,
                                    ),
                                    IconButton(
                                        icon: const Icon(Icons.delete),
                                        onPressed: () {
                                            setState(() {
                                                _saved.remove(word);
                                                savePrefs(_saved);
                                            });
                                        },
                                    )
                                ],
                            ),
                        );
                    },
                );

                final List<Widget> divided = ListTile.divideTiles(
                    context: context,
                    tiles: tiles,
                ).toList();

                return Scaffold(
                    appBar: AppBar(
                        title: const Text('Saved Suggestions'),
                    ),
                    body: ListView(children: divided),
                );
            },
        ),
    );
}

_saved.remove(word); inside setState doesn't remove the startup name instantly.

Should I make another stateful component? How do I solve it?

回答1:

That's because the widget you created inside builder is not Stateful.

Create a StatefulWidget and call it from the MaterialPageRoute.

Just a few changes:

void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) => FavoriteList(
            data: _saved, savePrefs: savePrefs, biggerFont: _biggerFont),
      ),
    );
  }

Create a new StatefulWidget

class FavoriteList extends StatefulWidget {
  final Set<String> data;
  final Function savePrefs;
  final TextStyle biggerFont;
  FavoriteList({Key key, this.data, this.savePrefs, this.biggerFont})
      : super(key: key);

  @override
  _FavoriteListState createState() => _FavoriteListState();
}

class _FavoriteListState extends State<FavoriteList> {
  Set<String> _saved;
  Future<SharedPreferences> _prefs = SharedPreferences.getInstance();

  @override
  void initState() {
    _saved = widget.data;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final Iterable<ListTile> tiles = _saved.map(
      (String word) {
        return ListTile(
          title: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Text(
                word,
                style: widget.biggerFont,
              ),
              IconButton(
                icon: const Icon(Icons.delete),
                onPressed: () {
                  setState(() {
                    _saved.remove(word);
                    widget.savePrefs(_saved);
                  });
                },
              )
            ],
          ),
        );
      },
    );

    final List<Widget> divided = ListTile.divideTiles(
      context: context,
      tiles: tiles,
    ).toList();

    return Scaffold(
      appBar: AppBar(
        title: const Text('Saved Suggestions'),
      ),
      body: ListView(children: divided),
    );
  }
}