Search code examples
flutterdarthook-widgets

List not updating after item added


In page A, I'm calling an API to get list data from server , then add it into list.

Page A code

Widget build(BuildContext context) { 

ValueNotifier<List> list = useState([]);

useEffect(() {
  WidgetsBinding.instance.addPostFrameCallback((_) {
    context
        .read<AgentVehiclesListCubit>()
        .getAgentVehiclesList(
            GetAgentVehiclesListParams(tenancyId: tenancy.id!))
        .whenComplete(() {
      final state = BlocProvider.of<AgentVehiclesListCubit>(context).state;
      if (state is AgentVehiclesListDone) {
        list.value = state.tenancy;  // add the output from server to list
      }
    });
  });

  return () {};
}, const []); 

When Button is pressed, pass the list to EditScreen.

InkWell(
   onTap: () {
     Navigator.pushNamed(
        context, TenancyRoutes.editScreen,
        arguments: list);
},

In EditScreen, there is a floatingActionButton for user to add vehicleItems. Once added, the item should be added into the list, and Listview should be refreshed.

class EditScreen extends HookWidget {
      final ValueNotifier<List<VehicleItems>> list;
    
      const EditScreen(this.list, {super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          floatingActionButton: FloatingActionButton(
              backgroundColor: AppTheme.light.colorScheme.primary,
              onPressed: () {
                Navigator.pushNamed(context, TenancyRoutes.createVehicleItemsScreen)
                    .then(((onValue) {
                  if (onValue is VehicleItems) {
                    debugPrint(onValue.toString());
                    list.value = [...list.value..add(onValue)]; // add new item into here
                  }
                }));
              },
              child: const Icon(
                Icons.add,
                color: Colors.white,
              )),
          appBar: AppBar(
              iconTheme: const IconThemeData(color: Colors.white),
              backgroundColor: AppTheme.light.colorScheme.primary,
              title: Text(
                'vehicles'.tr(),
                style: const TextStyle(color: Colors.white),
              ),
              actions: const []),
          body: _showBody(list),
        );
      }
    
      Widget _showBody(ValueNotifier<List<VehicleItems>> list) {
        return ListView.separated(
            padding: EdgeInsets.zero,
            shrinkWrap: true,
            separatorBuilder: (context, index) => Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Container(
                  color: Colors.grey.shade200,
                  height: 1,
                )),
            itemCount: list.value.length,
            itemBuilder: (context, index) {
              final items = list.value[index];
              return InkWell(
                  onTap: () {},
                  child: ListItemPadding(
                    child: VehicleItem(items),
                    // isDeleteVisible: false,
                  ));
            });
      }
    }

However, the listView remains unchanged unless I hot reload it. How to fix it?


Edit

I add useValueListenable(list); after list.value = [...list.value..add(onValue)];, get error

I/flutter ( 6061): [🌎 Easy Localization] [WARNING] Localization key [submit] not found
E/flutter ( 6061): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:flutter_hooks/src/framework.dart': Failed assertion: line 133 pos 12: 'HookElement._currentHookElement != null': Hooks can only be called from the build method of a widget that mix-in `Hooks`.
E/flutter ( 6061): 
E/flutter ( 6061): Hooks should only be called within the build method of a widget.
E/flutter ( 6061): Calling them outside of build method leads to an unstable state and is therefore prohibited.
E/flutter ( 6061): 
E/flutter ( 6061): #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
E/flutter ( 6061): #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
E/flutter ( 6061): #2      Hook.use (package:flutter_hooks/src/framework.dart:133:12)
E/flutter ( 6061): #3      use (package:flutter_hooks/src/framework.dart:18:32)
E/flutter ( 6061): #4      useValueListenable (package:flutter_hooks/src/listenable.dart:9:3)
E/flutter ( 6061): #5      EditAgentVehiclesListScreen.build.<anonymous closure>.<anonymous closure> (package:xxx/_edit_screen/edit_screen.dart:23:17)
E/flutter ( 6061): <asynchronous suspension>
E/flutter ( 6061):

Solution

  • You need to wrap your ListView to ValueListenableBuilder in order to listen to updates whenever it modifies the list (without using stateful widget)

    ValueListenableBuilder(
       valueListenable: list,
       builder: (_, vehicles, ___) => ListView.separated(
            padding: EdgeInsets.zero,
            shrinkWrap: true,
            separatorBuilder: (context, index) => Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Container(
                  color: Colors.grey.shade200,
                  height: 1,
                )),
            itemCount: vehicles.length,
            itemBuilder: (context, index) {
              final item = vehicles[index];
              return InkWell(
                  onTap: () {},
                  child: ListItemPadding(
                    child: VehicleItem(item),
                    // isDeleteVisible: false,
                  ));
            })
        );