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):
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,
));
})
);