How do you pass a callback function to a sibling component in React

Viewed 329

How do you pass a callback function to a sibling component such that a button in one can trigger an action in the another? The following code is an example of an attempt I made that ended up infinitely resetting the state in Index.js

import React, {useState} from "react"

const ComplexComponent = ({setCallbackFunction}) => {
    setCallbackFunction(() => console.log("hello world"))
    return <div/>
}

const Button = ({onClick}) => {
    return (
        <button onClick={onClick}>
            Submit
        </button>
    )
}

export default function Index() {
    const [callbackFunction, setCallbackFunction] = useState(() => {})

    // EXPECTED: callbackFunction should log "hello world" after clicking Button
    // ACTUAL: state is reset infinitely

    return (
        <>
            <ComplexComponent setCallbackFunction={setCallbackFunction} />
            <Button onClick={callbackFunction}/>
        </>
    )
}

1 Answers

In this case function is getting executed as soon as you initialize. example below, the function is not returning anything. its just printing initial immediately. Since its not returning anything, undefined will be set to callbackFunction variable.

const [callbackFunction, setCallbackFunction] = React.useState(() =>
    console.log('initial')
  );

solution: wrap the function with another function. so that, the outer function returns inner function instead of undefined

const [callbackFunction, setCallbackFunction] = React.useState(
    () => () => console.log('initial')
  );

now you can reset call back function, again with a wrapper function. without the wrapper same thing here as before. function will get executed immediately and print hello world

const ComplexComponent = ({ setCallbackFunction }) => {
  setCallbackFunction(() => () => console.log('hello world'));
  return <div />;
};

to avoid different component render error consider useEffect.

const ComplexComponent = ({ setCallbackFunction }) => {
  React.useEffect(() => {
    setCallbackFunction(() => () => console.log('hello world'));
  }, []);

  return <div />;
};

Related