Home > Back-end >  Data not updating with Provider, Flutter
Data not updating with Provider, Flutter

Time:02-18

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": "[email protected]",
        "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):

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.

CodePudding user response:

Why don't you wrap your Column inside a Consumer widget that listens to the UserStore.

Did you do it like this:

// remove fetching the provider using Provider.of;
// the Consumer widget is taking care of that for you.

return Consumer<UserStore>(
    builder: (context, userStore, child) {
        UserData user = userStore.getUserInfo(userId);
        
        return Column(
          children: [
             Text(user.firstName),
             Text(user.lastName),
          ],
        );
    }
);

every time you call notifyListeners on your UserStore it should cause this widget to rebuild itself, displaying the changes. Now, you're not showing where you're getting the userId either, which I'm wondering now as well.

CodePudding user response:

The line you highlighted

Your JSON and your UserData object use a UserData.id member but the line highlighted _userInfo[user.userId] = user; uses userId. If the class definition provided is correct then it should be user.id.

Other Provider stuff, maybe

You can use context.watch instead of Provider.of, but if Consumer doesn't work then it's not likely to change anything. (Provider as written in the code block won't trigger a re-render)

final userStore = context.watch<UserStore>();
    UserData user = userStore.getUserInfo(userId);
...
return Column(
children: [
    Text(user.firstName),
    Text(user.lastName),
   ],
);

Remember to insert a Provider into the Widget Tree

Perhaps make sure that Provider is properly inserted into the widget tree - the code samples above don't include that exact code. If it's missing then an approximation of what that should look like is as follows:

ChangeNotifierProvider(create: (context) => UserStore(), SomeParentWidget())
  • Related