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]);
you should destructure handleClick
outside of props
at the start of the component you probably have something like this:
const myComponent = (props) =>
change to
const myComponent = ({ handleClick, id })
basically you can pull out any props you know as their actual name
then use below like so:
useEffect(() => {
handleClick(id);
}, [id, handleClick]);
or probably you don't actually need the function as a dependency so this should work
useEffect(() => {
handleClick(id);
}, [id]);
Call the function with this
as null, like so:
useEffect(() => {
props.handleClick.call(null, id);
}, [id, props.handleClick]);
Everything should work as expected as long as props.handleClick doesn't point to a function or a method that uses this.
.
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.
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)
Add props.handleClick
as the dependency
useEffect(() => {
props.handleClick(id);
}, [id, props.handleClick]);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.