Nathan Gouy
Nathan Gouy

Reputation: 1412

setState not working with Navigator.of(context)

I am trying to play with the flutter Example app part 2. In a nutshell: Page one : It build a infinite list of words, where you can add / remove some to your favorite and there is a second page to list all the favorite words. We can access this second page through the actions: <Widget>[IconButton(icon: Icon(Icons.list), onPressed: _pushSaved)] of the app bar

enter image description here

I slightly modified the code so the second page uses the same list builder _buildWordsList , so they share the same layout / style and we can also click on words on second page to UNfavorite them.

Sadly when I click on a favorite word on the second page, though it removes it from the selected words, it still displays (as it was still favorite)

Here is the "important" code (and here is a gist with all the code):

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
    );
  }
}

class RandomWordsState extends State<RandomWords> {
  final List<WordPair> _suggestions = <WordPair>[];
  final List<WordPair> _saved = <WordPair>[]; // Add this line.
  # ...

  Widget _buildWordsList(WordPair itemAt(int index)) {
    return ListView.builder(
      ...
      itemBuilder: (BuildContext context, int i) {
        ...
        return _buildRow(item);
      },
    );
  }

  Widget _buildRow(WordPair pair) {

    return ListTile(
      title:  Text(pair),
      ...
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }

  WordPair _suggestionsBuilder(int index) {
    // ... fill suggestions if needed, then return related index suggestion
    return _suggestions[index];
  }

  WordPair _savedGetter(int index) {
    // ... check if index exists, return null if not
    return _saved[index];
  }

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          return Scaffold(
              appBar: AppBar(
                title: Text("Favorites suggestions"),
              ),
              body: _buildWordsList(_savedGetter));
        },
      ),
    );
  }

  @override // Add from this line ...
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
        actions: <Widget>[
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved)
        ],
      ),
      body: _buildWordsList(_suggestionsBuilder),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

In _pushSaved method which adds a MaterialPageRoute, even if I pass the context to the Navigator.of(context).push(, when I am on the "Saved suggestion" page, and click on an already saved suggestion and the row onTaped is triggered, the second list doesn't redraw itself. But I am sure it's removed from the _saved word list as when I come back on the General list, it's no more selected (the heart is no more red)

So The state is modified, but the page doesn't seems to be subscribed to changes once loaded / pushed. It only changes when I go back on home page then came back to saved suggestions. How Can I fix this?

Thank you for reading. I don't know where to ask for any help out there. Is there any discord / slack for this kind of stuff ?

Upvotes: 2

Views: 1474

Answers (1)

Stein.
Stein.

Reputation: 1544

This is no good architecture. The Navigazor.push() method pushed widgets on the Navigator stack. Since you do not pop the navigator stack anywhere, they just stack up. You should add a global variable that holds state data and just update the ui with setState. Look here for more info: documentation

Upvotes: 1

Related Questions