Make React Useeffect Hook Not Run on Initial Render

Make React useEffect hook not run on initial render

We can use the useRef hook to store any mutable value we like, so we could use that to keep track of if it's the first time the useEffect function is being run.

If we want the effect to run in the same phase that componentDidUpdate does, we can use useLayoutEffect instead.

Example

const { useState, useRef, useLayoutEffect } = React;
function ComponentDidUpdateFunction() { const [count, setCount] = useState(0);
const firstUpdate = useRef(true); useLayoutEffect(() => { if (firstUpdate.current) { firstUpdate.current = false; return; }
console.log("componentDidUpdateFunction"); });
return ( <div> <p>componentDidUpdateFunction: {count} times</p> <button onClick={() => { setCount(count + 1); }} > Click Me </button> </div> );}
ReactDOM.render( <ComponentDidUpdateFunction />, document.getElementById("app"));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>

useEffect does not run in initial render

The useEffect hook actually renders on initial component mount but the problem here is that the way you generate piano node .

You need to somehow put the value in a state and update state so the component re-renders everytime the state changes and also when the component mounts .

const [value , setValue ] = React.useState("1")

React.useEffect(() => {
// your logic
// setValue("2")
}, [value]);

Now the useEffect hook will run on component mount and then everytime the state value changes .

Note

If the value change simultaneously it will cause rendering problem in the component so a better option in this case is assigning an event listener in useEffect like this :

const handleScroll = () => {
// your logic
}

React.useEffect(() => {
if (typeof window !== "undefined"){
window.addEventListener("scroll" , handleScroll)
}
return () => {
// on component unmount remove event listener
if (typeof window !== "undefined"){
window.removeEventListener("scroll" , handleScroll)
}
}
}, []);

With useEffect, how can I skip applying an effect upon the initial render?

As the guide states,

The Effect Hook, useEffect, adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes, but unified into a single API.

In this example from the guide it's expected that count is 0 only on initial render:

const [count, setCount] = useState(0);

So it will work as componentDidUpdate with additional check:

useEffect(() => {
if (count)
document.title = `You clicked ${count} times`;
}, [count]);

This is basically how custom hook that can be used instead of useEffect may work:

function useDidUpdateEffect(fn, inputs) {
const didMountRef = useRef(false);

useEffect(() => {
if (didMountRef.current) {
return fn();
}
didMountRef.current = true;
}, inputs);
}

Credits go to @Tholle for suggesting useRef instead of setState.

UseEffect firing on initial render

You can wait until the key & device props are available:

useEffect(() => {
key && device && fetch(`APILINK&key=${key}&id=${device}`)
.then((res) => res.json())
.then(setData)
}, [device, key])

useEffect is called right after the first render, regardless of the dependency array, so this protection above will not run the fetch call until those variables are available (when the dependency array "sees" there was a change and calls the useEffect callback).

You might want to show a loader if the key prop might take a while to be available.


I suggest to de-couple the logic which gets the data from the useEffect, because you might want to call getData directly, and it's also better for testing and general code order.

const getData = (key, device) => 
key && device && fetch(`APILINK&key=${key}&id=${device}`)
.then((res) => res.json())
.then(setData);

useEffect(() => {
getData(key, device)
}, [device, key])

Also, there's no need to fornull in useState(null), because useState() will behave identical.

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

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?

Why is my useEffect not running on first render?

below code will not work as map need return statement, so it would be undefined, useEffect will console the empty array as define in the state. also you should not use let in render components as it will always initate, use may be useRef for that. also if your component consist js code, better to make it helper file and use it, would save and boost the performance.

 words.map(word =>{
if(word.length <= 2){
scrambledWord.push(word);

}
else{
scrambledWord.push(scrambleWord(word));
}
})

How to trigger an useEffect hook in React?

You can add props.id to dependency array so it would rerun on id change. Having an empty dependency array makes it run only once.

useEffect(() => {
async function fetchOne() {
const response = await productService.getOne(props.id)
setProduct(response.data)
}
fetchOne()
}, [props.id])


Related Topics



Leave a reply



Submit