简体   繁体   中英

How to use a prop function inside of UseEffect?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM