Flutter Provider `notifyListeners()` not updating after initial load

Issue

I am building a simple CRUD page in flutter. Right now my list loads initially but when I try to update it, It doesnt re-build the widget.

I have a class that is responsible for building a list of items retrieved from the database

class PlanList extends StatefulWidget {
  PlanList({Key key}) : super(key: key);

  @override
  _PlanListState createState() => _PlanListState();
}

class _PlanListState extends State<PlanList> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      Provider.of<PlansProvider>(context, listen: true).loadPlans();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<PlansProvider>(
      builder: (context, data, _) => ListView.builder(
        itemCount: data.items.length,
        itemBuilder: (BuildContext context, int index) {
          return Text(data.items[index].type);
        },
      ),
    );
  }
}

I also have a provider model that is responsible for updating the list.

class PlansProvider extends ChangeNotifier {
  List<Payload> _plansList = [];
  var _test = "test";

  get test => _test;
  UnmodifiableListView<Payload> get items => UnmodifiableListView(_plansList);

  loadPlans() {
    Plans _result;
    getPlans()
        .then((value) => _result = value)
        .then((value) => _plansList = _result.payload)
        .whenComplete(() => notifyListeners());
  }
}

Future<Plans> getPlans() async {
  final response = await http.get('http://10.0.2.2:8080/plans');

  if (response.statusCode == 200) {
    return Plans.fromJson(json.decode(response.body));
  } else {
    throw Exception(response.statusCode);
  }
}

and my function that calls the provider model function when I want to reload the items from the DB

class CreatePlansPage extends StatefulWidget {
  CreatePlansPage({Key key}) : super (key: key);

  @override
  _CreatePlansPageState createState() => _CreatePlansPageState();
}

class _CreatePlansPageState extends State<CreatePlansPage> {
  var _name = '';

  _handleTap(String string){
    setState(() {
      _name = string;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('$_name'),
      ),
      body: ListView(
        children: [
          ListTile(
            leading: Icon(Icons.add),
            title: Text("Dinner"),
            onTap: _handleTap('Dinner'),
          ),
          ListTile(
            leading: Icon(Icons.add),
            title: Text("Dinner"),
            onTap: _handleTap('Dinner'),
          ),
          Center(
            child: RaisedButton(
                onPressed: (){
                  setState(() {
                    createPlans(_name);
                    Navigator.pop(context);
                  });
                }
            ),
          )
        ],
      ),
    );
  }
}

createPlans(String name) async {
  final http.Response response = await http.post(
    'http://10.0.2.2:8080/plans',
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'type': name,
    }),
  );

  if (response.statusCode == 200) {
    PlansProvider().loadPlans();
  }

  if (response.statusCode != 200) {
    throw Exception('Failed!!!!');
  }
}

Does anyone know why this isn’t working? Am I missing something?

Solution

in your createPlans function you’re calling PlansProvider().loadPlans(); which is not the same that the one provided by calling Provider.of<PlansProvider>(context, listen: false).loadPlans();

RaisedButton(
  onPressed: () async{
    try{
      final bool created = await createPlans(_name);
      if(created) Provider.of<PlansProvider>(context, listen: false).loadPlans();
      Navigator.pop(context);
    } catch(e){
      print('there was a en error'); //do somehting with the error
    }
  }
),

createPlans(String name) async {
  final http.Response response = await http.post(
    'http://10.0.2.2:8080/plans',
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'type': name,
    }),
  );

  if (response.statusCode == 200) {
    return true; //or just return, somehting to tell you it worked
  }

  if (response.statusCode != 200) {
    throw Exception('Failed!!!!');
  }
}

Also in your initState change the listen to false, to avoid the code to run more than once

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  Provider.of<PlansProvider>(context, listen: false).loadPlans();
  // if you use true then everytime notifyListeners fires it will run this code, which is undesirable
});

Answered By – EdwynZN

Answer Checked By – Gilberto Lyons (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.