Why does useEffect hook with its dependencies run after first component render

Viewed 1568

I have configured the useEffect to run only when its dependencies changes:

useEffect(() => {
        localStorage.setItem("cart", JSON.stringify(cart));

    }, [cart])

But when the component renders for the first time. useEffect hook will call Why?

3 Answers

That's just how useEffect works. All callbacks will run when the component mounts no matter the dependency array - no matter what values are in it, no matter whether it's empty, no matter whether it's even present at all.

If you want to avoid this, you can check if the cart is equal (===) to the cart's initial value.

const [cart, setCart] = useState(initialCart);
useEffect(() => {
    if (cart !== initialCart) {
        localStorage.setItem("cart", JSON.stringify(cart));
    }
}, [cart]);

In the case where comparing directly could produce false positives - like if the state was a primitive rather than an array, and so could be === to the initial value despite not being in the initial render - you'll need another way to check whether the component's mounted or not, such as by having an isMounted state or ref.

useEffect run at least one time to prevent that you should use a state to detect the first render in your component.

const [cart, setCart]=useState(initialCart);
const [didRender, setDidRender]=useState(false);

useEffect(()=>{
  setDidRender(true);
},[]);

useEffect(()=>{
  if(didRender){
    //Your code
  }
},[cart]);

I have prevent mounting using this:

let storageRef = useRef(true);
    useEffect(() => {
        if (!storageRef.current) {
            localStorage.setItem("cart", JSON.stringify(cart));
        }
        return () => { storageRef.current = false; }

    }, [cart])

Is it a good idea?

Related