-
-
Notifications
You must be signed in to change notification settings - Fork 188
Description
Describe the bug
useEffect() with non primitive values used in dependencies causes unwanted side effects.
For example a list in a parent component is passed to a child component, which is used as a dependency of a useEffect.
When that child component updates the state, the useEffect callback gets called again, while the list has not changed one bit.
The only way to prevent what seems to me an incorrect behaviour is to do [list.toString()]
I guess useEffect works on reference to compare data, and therefore when converting array to string, it's working as expected because it's a primitive value.
To Reproduce
Let's say I have a parent component with an array of string like
List<String> list = ["a", "b", "c"]
Then I have a child component
class SimpleComponent extends HookWidget {
final List<String> list;
const SimpleComponent({required this.list, super.key});
@override
Widget build(BuildContext context) {
final my_list = useState<List<String>>(list);
useEffect(() {
list.value = list;
return () {
print("unmount");
};
}, [list]);
return CustomTextButton(
onPressed: () {
list.value = [...list.value, "hello"]
},
textColor: Colors.red,
text: "Add more text to the list");
}
}
The example above will trigger side effects every single time you modify the list in the child component, while the list coming from the parent has not changed at all.
This is a big problem, when you have complex component where a variable can be updated from the parent and the children.
this behaviour can totally break the consistency of the component.
the only way to fix it is:
useEffect(() {
list.value = list;
return () {
print("unmount");
};
}, [list.toString()]);
Expected behavior
If an array, or object is used as a dependency in useEffect, there should not be any side effect as long as the dependency has not changed.
I come from react world and it's an issue I already experienced and I think back then I had used another library (use-deep-compare), which allowed to actually compare object and array rather than just primitive values