React: Modify Parent State While Child Renders

Hooks are usually much nicer than classes, so I’m trying to pass down the ability to set a parent’s state in a child of that parent using hooks. Specifically, I’m doing something like this:

class Parent extends Component {

    render = () => {
        return <>
           <Child useRegisterFoo={foo => {...;this.setState(foo);...;}} />
           { renderBasedOnRegister() }
           </>
    }
}

The goal is to be able to define the child like this:

const Child = ({useRegisterFoo}) => {
     useRegisterFoo(1);
     useRegisterFoo(2);
}

I will define many such children, and thus having such a simple useRegisterFoo to register a particular property of the child would be really useful.

The problem is that react complains if it’s done this way, understandably, as I’m modifying the state of the parent while the parent is being rendered. Specifically it says:

Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.

What’s a better approach at this problem? My main goal is to make the API from the perspective of the child as convenient as possible.

Answer

You are invoking the callbacks directly in the function body. This is an unintentional side-effect and shouldn’t be done. Even in function components you still need to work with the component lifecycle.

Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.

The entire body of a function component is the “render” function. Use the useEffect hook to invoke these passed callbacks, or conditionally call them as part of an event handler.

Example:

Use an useEffect hook with an empty dependency array to trigger the effect only once when the component mounts.

const Child = ({useRegisterFoo}) => {
  useEffect(() => {
    useRegisterFoo(1);
    useRegisterFoo(2);
  }, []); // <-- empty dependency, effect triggered once on mount
  ...
}