React Useeffect in Depth/Use of Useeffect

React , why is this useEffect being triggered on load?

By default, useEffect always runs after the first render.

The dependency array in useEffect lets you specify the conditions to trigger it. If you provide useEffect an empty dependency array, it’ll run exactly once.

If you want to trigger only after setNumberOfPages is triggered for the first time then the way you're using it is right:

useEffect(() => {
if (numberOfPages != null) {
const newArr = splitArray(issues, numberOfPages);
console.log('new arr');
console.log(newArr);
}
}, [numberOfPages]);

Additionally, you can check out this awesome StackOverflow answer: https://stackoverflow.com/a/59841947/16420018

And this article by Dan Abramov:
https://overreacted.io/a-complete-guide-to-useeffect/

How to fix this Maximum depth exceeded error with useEffect and useState?

Because you are executing useEffect callback whenever data changes and you are changing data in useEffect callback.

Remove data as dependency.

Use this code to fix it

const SingleTable = () => {
const events = useSelector(state => eventsSelector(state));
const [data, updateData] = useState([]);
const [sortCol, updateSortCol] = useState(0);
const [sortDir, updateSortDir] = useState('ascending');

useEffect(() => {
const formattedArray = events ? formatLoss(events): [];

events && updateData(formattedArray);
}, [events]);

//...

Maximum depth exceeded while using useEffect

what you are doing here is fetching a product list and filtering it based on the query string and using that filtered list to render the UI. So ideally your filteredList is just a derived state based on your queryString and productList. So you can remove the filterProducts from your useEffect and move it outside. So that it runs when ever there is a change in the state.

function filterProducts (productName = '', productList = []) {
return productName.trim().length > 0 ? productList.filter((prod)=> {
return prod.title === productName;
}); : productList
}

function HomePage () {
const [productList, setProductList] = useState([]);
const [queryString, setQueryString] = useState('');


useEffect(() => {
if (queryString.trim() === "") {
Axios.get("http://localhost:3001/api/product/get-all").then((data) => {
setProductList(data.data);
});
}
}, [queryString]);

// query products is the derived state
const queryProducts = filterProducts(queryString, productList);

// Now instead of using productList to render something use the queryProducts
return (
{queryProducts.map(() => {
.....
})}
)

If you want the filterProducts to run only on change in queryString or productList then you can wrap it in useMemo

const queryProducts = React.useMemo(() => filterProducts(queryString, productList), [queryString, productList]);

When to use useEffect?

You showed two different examples,

handleButtonClick fires on Button 1 click, while useEffect fires on every state change state (according to the dependency array).

In the next example, you notice that useEffect will log on every button click (Button 1/2), and handleButtonClick will log only on Button 2 click.

import React, { useState, useEffect } from "react";

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

useEffect(() => {
console.log(`You rendered ${count} times`);
}, [count]);

const handleButtonClick = () => {
setCount(count + 1);
console.log(`You clicked ${count + 1} times`);
};

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Button 1</button>
<button onClick={handleButtonClick}>Button 2</button>
</div>
);
}
  • Check similar question on useEffect use cases
  • Refer to useEffect docs

Why does useEffect dependencies on destructed props cause maximum update exceeded?

When ids is passed as a prop, the only time the local ids variable will have had its reference changed will be when the prop changes.

When it's not passed as a prop, the default assignment, since it runs inside the function, every time the function runs, produces a new empty array every time. So, if the function component updates once, it'll try to continue updating forever because the default empty array reference keeps changing.

One way to fix this would be to put the empty array outside the component. (Just make sure not to mutate, as always in React)

const emptyArr = [];
function Test1(props) {
const { ids = emptyArr } = props;
const [evenIds, setEvenIds] = useState<string[]>([]);

useEffect(() => {
const newEvenIds = ids.filter(id => id % 2 === 0);
setEvenIds(newEvenIds);
}, [ids])

return (<span>hello</span>)
}

State shouldn't be duplicated in more than one place though. useMemo would be more appropriate than a separate state and useEffect IMO.

const emptyArr = [];
function Test1(props) {
const { ids = emptyArr } = props;
const evenIds = useMemo(() => ids.filter(id => id % 2 === 0), [ids]);
return (<span>hello</span>)
}


Related Topics



Leave a reply



Submit