I’ve an object like the following:
{
"selectedProducts": [
{
"selectionId": 1722249608951,
"productId": "8174367932666",
"variants": [
{
"variantId": "45186237989114",
"price": "17.99",
"title": "Chicken",
"quantity": 1
},
{
"variantId": "45186238021882",
"price": "18.99",
"title": "Beef",
"quantity": 1
},
{
"variantId": "45186238054650",
"price": "16.99",
"title": "Mushroom",
"quantity": 1
}
],
"productTitle": "Burger"
},
{
"selectionId": 1722249804165,
"productId": "8174367932666",
"variants": [
{
"variantId": "45186237989114",
"price": "17.99",
"title": "Chicken",
"quantity": 1
},
{
"variantId": "45186238021882",
"price": "18.99",
"title": "Beef",
"quantity": 1
}
],
"productTitle": "Burger (2)"
}
]
}
Now I wanna trigger the useEffect
when the variants count inside the selectedProducts
is changed. So I initially tried doing the following:
useEffect(() => {
// Some Operations
setFormState((prevState) => ({
...prevState,
...productOptions,
}));
}, [
...formState.selectedProducts.map((product) => product.variants.length)
]);
But this produces a error like: Warning: The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.
So the way-around I implemented was to take another state
that will store the total number of variants and then pass selectedProducts
as dependency of another useEffect
which will then change the totalVariantsCount
. Then pass the totalVariantsCount
as the dependency of the main useEffect
that I wanted to trigger in the place when the variants count changed.
const [totalVariantsCount, setTotalVariantsCount] = useState(0);
useEffect(() => {
const variantsCount = formState.selectedProducts.reduce(( acc, product ) => acc + product.variants.length, 0);
setTotalVariantsCount(variantsCount);
}, [formState.selectedProducts]);
To check it I implemented the following:
useEffect(() => {
console.log(`totalVariantsCount changed: ${totalVariantsCount}`);
// REMOVE: Putting the value in the formState just for test, remove it when releasing.
setFormState((prevState) => ({ ...prevState, totalVariantsCount }));
}, [totalVariantsCount]);
This works for now but acts strange sometimes like – when this useEffect
is triggered after the totalVariantsCount
is changed, it consoleLogs
the correct value every-time but changes the totalVariantsCount
in the main formState
only when the selectedProducts
count is changed not when the variants count is changed.
So I was wondering what is the proper way to trigger a useEffect
on change of a deeply nested object.
Thanks!
2
Answers
i think you need to use your whole array and have further checking inside the useeffect this answer can help:
The problem here is not deeply nested object property but that you try to depend on a field that doesn’t exist and change dynamically
So creating a state to manage it is good idea.
Otherwise you can possibly explicitly change the whole array outside of the component. Like on each change outside send
...yourArray
to the component so every time it changes, it will be a new pointer and then you’ll be able to use[yourArray]
as a dependency foruseEffect