I want to call a prop function inside of UseEffect. The following code works:
useEffect(() => {
props.handleClick(id);
}, [id]);
But lint is complaining about props
not being a dependency.
If I do this, then the code no longer works and I have maximum re-render error:
useEffect(() => {
props.handleClick(id);
}, [id, props]);
How can I fix the lint issue?
Sample code:
Parent Component
const ParentGrid = ({rows, columns}) => {
const [selection, setSelection] = useState(null);
const handleClick = selectedRows => {
setSelection(selectedRows.map(i => rows[i]));
};
return (
<ChildGrid
columns={columns}
data={data}
handleClick={handleClick}
/>
Child Component
const ChildGrid = props => {
const {data, handleClick, ...rest} = props;
useEffect(() => {
handleClick(selectedRows);
}, [selectedRows]);
Just like the state, we can also use props as a dependency to run the side effect. In this case, the side effect will run every time there is a change to the props passed as a dependency. useEffect(() => { // Side Effect }, [props]);
I want to call a prop function inside of UseEffect. The following code works: useEffect(() => { props. handleClick(id); }, [id]);
The function passed to useEffect is a callback function. This will be called after the component renders. In this function, we can perform our side effects or multiple side effects if we want.
If we just want to run the useEffect function after the initial render, as a second argument, we can give it an empty array. If we pass a second argument (array), React will run the callback after the first render and every time one of the elements in the array is changed.
I see alot of weird and incorrect answers here so I felt the need to write this.
The reason you are reaching maximum call depth when you add the function to your dependency array is because it does not have a stable identity. In react, functions are recreated on every render if you do not wrap it in a useCallback
hook. This will cause react to see your function as changed on every render, thus calling your useEffect function every time.
One solution is to wrap the function in useCallback
where it is defined in the parent component and add it to the dependency array in the child component. Using your example this would be:
const ParentGrid = ({rows, columns}) => {
const [selection, setSelection] = useState(null);
const handleClick = useCallback((selectedRows) => {
setSelection(selectedRows.map(i => rows[i]));
}, [rows]); // setSelection not needed because react guarantees it's stable
return (
<ChildGrid
columns={columns}
data={data}
handleClick={handleClick}
/>
);
}
const ChildGrid = props => {
const {data, handleClick, ...rest} = props;
useEffect(() => {
handleClick(selectedRows);
}, [selectedRows, handleClick]);
};
(This assumes the rows
props in parent component does not change on every render)
One correct way to do this is to add props.handleClick
as a dependency and memoize handleClick on the parent (useCallback) so that the function reference does not change unnecessarily between re-renders.
It is generally NOT advisable to switch off the lint rule as it can help with subtle bugs (current and future)
in your case, if you exclude handleClick from deps array, and on the parent the function was dependent on parent prop or state, your useEffect will not fire when that prop or state on the parent changes, although it should, because the handleClick function has now changed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With