skip to Main Content


export const FoodContextProvider = (props) => {
  const [selectedFoods, setSelectedFoods] = useState([]);
  const [newFood, setNewFood] = useState({});
  const [mode, setMode] = useState(null);
  const [length, setLength] = useState(selectedFoods.length);

  useEffect(() => {
    if (mode === "add") {
      const duplicate = selectedFoods.some((item) => item.id === newFood.id);
      if (duplicate) {
        selectedFoods.forEach((item) => {
          if (item.id === newFood.id) {
            item.amount = newFood.amount;
          }
        });
      } else {
        setSelectedFoods((prevFoods) => {
          return [...prevFoods, newFood];
        });
      }
    } else {
      selectedFoods.forEach((item) => {
        if (item.id === newFood.id) {
          item.amount = newFood.amount;
        }
      });
      if (newFood.amount < 1) {
        setSelectedFoods((prevFoods) => {
          return prevFoods.filter((food) => food.id !== newFood.amount.id);
        });
      }
    }
    console.log(selectedFoods);
  }, [newFood, mode, selectedFoods, setSelectedFoods]);

  const selectingFood = (food) => {
    setLength((pre) => pre + 1);
    setNewFood(food.newFoodItem);
    setMode(food.mode);
  };

  return (
    <FoodContext.Provider
      value={{
        foodItems: foodItem,
        selectingFood: selectingFood,
        selectedFoods: selectedFoods,
        selectedItemLength: length,
      }}
    >
      {props.children} {/* App componnet */}
    </FoodContext.Provider>
  );
};

hi this is my product count code ,
by calling + button ,it will add product object to the list of selectedFoods state ; and decrease the amount of the products by calling – button
i face infinite loop when i want to remove the product item wich has amount of zero ;
by filtering this object from list of selected products leads to problem
here is what cause problem

    if (newFood.amount < 1) {
        setSelectedFoods((prevFoods) => {
          return prevFoods.filter((food) => food.id !== newFood.amount.id);
        });
      }

how to prevent this ?

2

Answers


  1. You shouldnt add a lot of dependencies on useEffect, break it to multiple useEffect and verify

    Login or Signup to reply.
  2. There are a couple of issues with that useEffect (and some question about whether it should be an effect at all; more on that below):

    1. You’re using selectedFoods as a dependency, but calling setSelectedFoods in the effect. That’s what causes the infinite loop.

    2. You’re modifying objects in selectedFoods instead of creating a new objects, which breaks the primary rule of state: Don’t directly modify state items. More in the docs.

    3. You’re modifying state based on existing state, but the existing state could be stale.

    4. Harmless, but: there’s never any need to list useState state setter functions like setSelectedFoods in dependency arrays; they’re guaranteed to be stable for the lifetime of the component instance.

    Instead, pass a callback into setSelectedFoods so it calls your code with the up-to-date array. Then you don’t need the array as an effect dependency, and you’re never working with a stale copy. Something like this:

    useEffect(() => {
        if (mode === "add") {
            // *** Using the callback form, we don't have a dependency on `selectedFoods` anymore
            setSelectedFoods((selectedFoods) => {
                const duplicate = selectedFoods.some(
                    (item) => item.id === newFood.id
                );
                if (duplicate) {
                    // *** Creating a new array
                    return selectedFoods.map((item) => {
                        if (item.id === newFood.id) {
                            // *** Creating a new object
                            item = { ...item, amount: newFood.amount };
                        }
                        return item;
                    });
                } else {
                    setSelectedFoods((prevFoods) => {
                        return [...prevFoods, newFood];
                    });
                }
            });
        } else {
            // *** Again, using the callback form
            setSelectedFoods((selectedFoods) => {
                if (newFood.amount < 1) {
                    return selectedFoods.filter(
                        (food) => food.id !== newFood.amount.id
                    );
                } else {
                    // *** Creating a new array
                    return selectedFoods.map((item) => {
                        if (item.id === newFood.id) {
                            // *** Creating a new object
                            item = { ...item, amount: newFood.amount };
                        }
                    });
                }
            });
        }
    }, [newFood, mode]);
    

    Now the effect is only triggered when newFood or mode changes.

    But stepping back: It seems very odd to have an effect adding and removing items from your selectedFoods array. That seems like something that should be happening as a direct action, not as an effect, though of course it’s hard to say without a broader context.

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