skip to Main Content

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


  1. 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 (via currentState.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 what formState.selectedProducts is).

    The whole deep-copy of formState with JSON stringifying/parsing is unnecessary, though. You should just directly use formState.selectedProducts, á la

    if (actionData && actionData?.target === "productVariants" && formState.selectedProducts.length > 0) {
    

    and 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 that formState.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:

    const selectedProducts = formState.selectedProducts;
    
    const { loading, variantsAndQty, allProductVariants } = React.useMemo(() => {
      if (actionData?.target === "productVariants" && selectedProducts.length > 0) {
        // Finding the product from the formStates selectedProducts array
        const selectedProduct = 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,
        }));
        return {
          loading: false,
          variantsAndQty: selectedVariantIdsAndQty,
          allProductVariants: actionData,
        };
      } else {
        return {
          loading: true,
          variantsAndQty: [],
          allProductVariants: [],
        };
      }
    }, [actionData, selectedProducts]);
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search