What’s the recommended approach for determining which states to include in useEffect’s dependency array?
I thought I should only pass states that I wanna watch over for changes and fire the useEffect based on those changes.
For example in the following useEffect I only passed actionData on the dependency list as I this useEffect needs to be fired when I get some specific actionData. But I’m getting the following warning: React Hook useEffect has a missing dependency: 'formState'. Either include it or remove the dependency array.
The context of the useEffect: This useEffect is used to populate data for an edit modal. The modal allows users to modify a product’s selected variants. Triggered by an ‘edit’ button click, a POST request is made to a Remix action, and the response is fetched using const actionData = useActionData();
. The useEffect should only run when productVariants
data is available from the action.
There is no need to fire the useEffect on changes of the formState
properties unless I get productVariants
data from the action.
useEffect(() => {
const currentState = JSON.parse(JSON.stringify(formState));
if (actionData && actionData?.target === "productVariants" && currentState.selectedProducts.length > 0) {
// Finding the product from the formStates selectedProducts array
const selectedProduct = currentState.selectedProducts.find(product => product.selectionId === actionData.selectionId );
const selectedVariantIdsAndQty = selectedProduct?.variants.map(variant => ({
variantId: variant.variantId,
variantQty: variant.quantity,
title: variant.title,
price: variant.price,
selectedOptionsValue: variant.selectedOptionsValue,
})); // Extract already selected product variants Id and qty
// Setting the selected variants with id and qty in the selectedVariants array
setSelectedProductVariantsAndQty(selectedVariantIdsAndQty);
// Setting all variants of this product in the allProductVariants array
setAllProductVariants(actionData);
// Setting modal loading state to false.
setModalLoading(false);
}
}, [actionData]);
Thanks!
2
Answers
In short: any data that affects the computation of the effect.
ESLint is warning you because it clearly looks like
formState
affects what that function does (viacurrentState.selectedProducts
).If
formState
isn’t a dependency for that effect, that effect won’t be re-run when you change the selected products in the form (or at least that’s what I’d assume whatformState.selectedProducts
is).The whole deep-copy of
formState
with JSON stringifying/parsing is unnecessary, though. You should just directly useformState.selectedProducts
, á laand then have
[actionData, formState.selectedProducts]
as your dependencies to avoid the effect running every time anything in the form state changes. (This of course assumes thatformState.selectedProducts
doesn’t get mutated internally, like are the rules with any and all state atoms in React.)Chances are, though, that this shouldn’t be an effect at all, but an
useMemo
to simply derive more data from some other state. It’s hard to tell without more context, but here’s what it could look like as such:I think it’s because the formState is an object that contains information about the entire form state. And it helps you keep track of the user’s interaction with the form. For example, it could be isDirty or dirtyFields.