9

I'm using Provider in my flutter app, and when I go to a new page, the data provided to the Provider at page 1 is not accessible in page 2.

The way I understood the way Provider works, was that there is a central place where one stores all the data, and one can access that data anywhere in the application. So in my application, which is shown below, ToDoListManager is the place where all the data is stored. And if I set the data in Page 1, then I will be able to access that data in Page 2, and vice versa.

If this is not correct, then what part is wrong? And why isn't it working in my application?

Here's the code

Page 1

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      builder: (context) => ToDoListManager(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('Cool Project'),
        ),
        body:e ToDoList(),
      ),
    );
  }
}

class ToDoList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final toDoListManager = Provider.of<ToDoListManager>(context);

    return ListView.builder(
      itemCount: toDoListManager.toDoList.length,
      itemBuilder: (context, index) {
        return GestureDetector(
          onTap: () {
            Navigator.push(context,
                MaterialPageRoute(builder: (context) => Details(index)));
          },
          child: Text(toDoListManager.toDoList[index]),
        );
      },
    );
  }
}

Page 2

class Details extends StatelessWidget {
  final int index;

  Details(this.index);

  @override
  build(BuildContext context) {
    return ChangeNotifierProvider(
      builder: (context) => ToDoListManager(),
      child: Scaffold(
          appBar: AppBar(
            title: Text('Details Bro'),
          ),
          body: AppBody(index)),
    );
  }
}

class AppBody extends StatelessWidget {
  final int index;

  AppBody(this.index);

  @override
  Widget build(BuildContext context) {
    final toDoListManager = Provider.of<ToDoListManager>(context);
    print(toDoListManager.toDoList);

    return Text(toDoListManager.toDoList[1]);
  }
}

ToDoListProvider

class ToDoListManager with ChangeNotifier {
  List<String> _toDoList = ['yo', 'bro'];

  List<String> get toDoList => _toDoList;

  set toDoList(List<String> newToDoList) {
    _toDoList = newToDoList;
    notifyListeners();
  }
}
Jessica
  • 9,379
  • 14
  • 65
  • 136
  • [This question similar with simple example](https://stackoverflow.com/questions/62148419/is-possible-update-value-cross-pages-by-using-provider-in-flutter) – Huy Tower Jul 21 '20 at 03:05

1 Answers1

9

You have 2 options:

  1. Place your ChangeNotifierProvider above your MaterialApp so that is accesible from any of you Navigator routes.

  2. Keep your Home widget as is but when pushing the new widget with the Navigator provide the original Manager.

onTap: () {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) {
                return Provider<ToDoListManager>.value(
                    value: toDoListManager,
                    child: Details(index),
                );
            },
        ),
    );
},

With both approaches you don't need to create a new ChangeNotifierProvider in your details screen.

Martyns
  • 3,605
  • 22
  • 33
  • Using the approach of placing the `ChangeNotifierProvider` above the `MaterialApp`, will the entire app reload upon value change? – Jessica Sep 17 '19 at 14:54
  • 1
    No, only the widgets that make use of Provider.of(context) or Consumer. Placing them above the MaterialApp is just a matter of scope. If you have a provided value that make sense inside a screen you could have it in an specific screen widget – Martyns Sep 17 '19 at 22:07
  • 1
    Thank you! And the diff between consumer and provider, is that consumer is for a ui change such as a radio button/tab, vs a provider, which will update data and thereby update the ui? – Jessica Sep 17 '19 at 22:25
  • Simple, a Provider.of will rebuild calling the build method and a Consumer will rebuild calling its property builder https://pub.dev/packages/provider#faq – Martyns Sep 18 '19 at 12:07
  • Thank you Martyns for the explanation! – Jessica Sep 18 '19 at 14:26
  • I think does not need to insert `Provider.value()` – Huy Tower Jul 21 '20 at 03:06
  • @HuyTower You do if your Provider is not above MaterialApp. Otherwise the navigation creates a "branch" in the widget tree where that provider does not exist. – Martyns Jul 21 '20 at 07:38
  • Okay, I see, I think insert `MultiProvider` above `MaterialApp` is a good idea also./ – Huy Tower Jul 22 '20 at 03:04