Search code examples
flutterdartriverpodhook-widgets

Flutter HookWidget doesn't rebuild when values changed


Here i used very simple HookWidget and Riverpod, when i call some methods of StateNotifierProvider such as increment i expect my widgets which i used useProvider rebuild again, for example:

class MyHomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final _orderProvider = useProvider(orderStateNotifierProvider.notifier);
    final List<SelectedProductServices> _serviceList = _orderProvider.getServices();
    return Scaffold(
        appBar: AppBar(
          title: Text('test'),
        ),
        body: Center(
          child:
          Consumer(
            builder: (_, watch, __) {
              return Column(
                children: <Widget>[
                  //...
                    GestureDetector(
                      onTap: () => _orderProvider.increment(productId: 1, serviceId: 1),
                      child: Container(
                          width: 200.0,
                          height: 50.0,
                          child: Text('ADD')),
                    )
                 //...
                ],
              );
            },
          ),
        ));
  }
}

here after clicking on button increment work fine, but _orderProvider doesn't trigger screen, i tried to use both of using Consumer and not using Consumer. in all time screen can't rebuild


Solution

  • In the methods try to create new instances of List<SelectedProductServices> like here:

      void increment({int productId,int serviceId}) {
        state = [// Generate a new list with current items in state
          for (final selectedService in state)
            if (selectedService.id == productId&&selectedService.sId==serviceId) 
              SelectedProductServices(
               //Create a new object with the updated internal state
              )
            else
              selectedService,
        ];
      }
    

    Dart compares its objects by reference, not by value and when you mutate the internal state of the List the reference it occupies in memory is the same regardless of the amount of items it has. If the list was held inside a class you could override the == method to compare the List<SelectedProductServices> using DeepCollectionEquality but when you are working directly with the List object you can only create a new list with a different reference in memory so that oldState!=newState

    Note: you should make all methods that modify internal state and that you want to update the UI and notify its listeners to work as above.