Search code examples
fluttermobileflutter-providerflutter-state

Data not updating with Provider, Flutter


After the user changes the data, the UI doesn't update the data with Provider. The API calls are always statusCode: 200 but the UI is not updating unless I refresh/build the page again. I assume that the setting state method is not set up correctly by me but I'm not sure what I did wrong. The code:

Method for editing profile info:

 Map<String, dynamic> userData;
@override
  Widget build(BuildContext context) {
UserData user = UserData.fromJson(userData);

return TextButton(
        onPressed: () async {
             changeUserInfo(user) // I pass the user object to the method
               .whenComplete(() => Navigator.of(context).pop());
          },
            child: Text(
             'SAVE',
             ),
       );
}

Change user method:

 Future<void> changeUserInfo(UserData user) async {
    final userRes = await patchUserInfo(user); // API CALL WHICH ALWAYS GOES THROUGH
    if (userRes != null) {
 // HERE IS WHERE I WANT TO SET THE CURRENT STATE OF THE USER THAT HAS BEEN CHANGED
     userStore.setUserInfo(user);  
      return;
    }
  }

The User Store:

class UserStore extends ChangeNotifier {

  Map<String, UserData> _userInfo = {};
  Map<String, UserData> get userInfo => _userInfo ;

 void setUserInfo(UserData user) {
    _userInfo[user.id] = user; // I assume this is where I do something wrong?!
    notifyListeners();
  }

UserData  getUserInfoByUserId(String userId) => _userInfo[userId];
}

The is the JSON from the API returned after patch:

{
    "statusCode": 200,
    "message": "Success",
    "data": {
        "id": "1",
        "email": "johndoe@johndoe.com",
        "firstName": "John",
        "lastName": "Doe",
    }
}

And my User Model:

class UserData {
  String id, firstName,
      lastName,
      email;

  UserData({
    this.id,
    this.firstName,
    this.lastName,
    this.email,
  });

  UserData.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    firstName = json['firstName'];
    lastName = json['lastName'];
    email = json['email'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data['id'] = this.id;
    data['firstName'] = this.firstName;
    data['lastName'] = this.lastName;
    data['email'] = this.email;

    return data;
  }
}

Let's say the screen where I should see the changes (I tried even with Consumer, so it is the same):

class SomeClassExample extends StatelessWidget {
final userStore = Provider.of<UserStore>(context, listen: false);
    UserData user = userStore.getUserInfo(userId);
...
return Column(
children: [
    Text(user.firstName),
    Text(user.lastName),
   ],
);

}

The way it is set now (or at least I think so), I pass the user object to the changeUserInfo method, where the object is passed to the API call and if the returned API call is not null, set the current state of the user info with the passed object. Then in the store I pass that object into my UserData map, notify the listeners, update it where it is listened and that's it. I'm not sure what I did wrong.

Thanks in advance for you help.


Solution

  • At this line:

    final userStore = Provider.of<UserStore>(context, listen: false);
    

    Use listen: true instead.

    That should make it update.

    As per the docs, the listen: false flag allows you to read a value from the Provider Store without observing it for changes. It is commonly used to optimise the application to avoid unnecessary rebuilding.