Search code examples
flutterflutter-provider

Unexpected change in the value of a StreamProvider, after I change the value of a copy variable


I assign the value of my streamProvider to a new variable object usersList... then I change a property tel in that newly created variable... but, surprise... the Provider itself also changes and I can no longer access the last value of that stream... strange... I thought that flutter is by value not by reference...

Otherweise, my StreamProvider seems properly wired to my Firestore: when value in DB is changed, it propagates properly to app which is the expected behaviour.

Help... How can I change my object copy without interfering with the Provider?

Code:

@override  Widget build(BuildContext context) {
    print("===== initial provider value: ${Provider.of<UsersList>(context).item("jaiKMOS5EHRTxc8wlorpNyLruf1").tel}");
    UsersList usersList = Provider.of<UsersList>(context); //I create a brand new variable where I assign value of Provider
    usersList.item("jaiKMOS5EHRTxc8wlorpNyLruf1").tel = "NewVal";  //I change my own local variable (not expecting Provider to change

    // ***** Why does the following value change ????
    print("===== updated provider value: ${Provider.of<UsersList>(context).item("jaiKMOS5EHRTxc8wlorpNyLruf1").tel}");
    return Text("");
}

Log:

I/flutter ( 7477): ===== initial provider value: 511-822-5571

I/flutter ( 7477): ===== updated provider value: NewVal

StreamProvider:

  @override  Widget build(BuildContext context) {
    return StreamProvider<UsersList>(
      create: (context) => _dbService.getUsersStream, initialData:null,
      child: HomePage());
  }

Solution

  • The variable is just a placeholder. You have an object and the variable just stores that object there. 2 variables can point to the same object, and that's what's happening.

    When you call Provider, it will just give you back a reference to an object (UsersList), that you defined inside the Provider constructor (_dbService.getUsersStream). Since you are using create:, Provider will call that creation function lazily (when you need it for the first time), and then it will store that value internally. create WILL NOT be called each time you call Provider.of<UsersList>(context).

    So your variable usersList points to the same object that Provider holds internally.