I have a child component that need to listen to one of its parent event
. More precisely, I have a function in the child component that takes as parameter an event
from the parent. I would like to call this function everytime the event
occurs.
As an example, here is a code snippet:
class Parent extends React.Component {
handleKeyDown = (event) => {
// Call the child function doSomething()
}
render() {
return (
<input
type="text"
onKeyDown={this.handleKeyDown}
>
<Child />
)
}
}
class Child extends React.Component {
doSomething = (event) => {
// Get the event from parent
}
render() {
return (
...
)
}
}
I have considered two ways to do it:
ref
to call the child function from the parent onKeyDown
state
to store the event and pass it as a props
to the child, then listen to props
changes with getDerivedStateFromProps
.However, none of these solutions seems very appealing. I have also thought about using a redux function but I need data from the child component as well as the event
from the parent component... I was wondering if there is a clean way do to that?
I updated my components to use hooks and ended up using useRef(), useImperativeHandle() and forwardRef() (the latter only for React < 19) to handle this case:
const Parent = () => {
const childRef = useRef();
const handleKeyDown = (event) => {
// Call the child function doSomething()
childRef.current.doSomething(event);
};
return (
<input
type="text"
onKeyDown={handleKeyDown}
>
<Child ref={childRef} />
);
};
// React < 19
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
doSomething: (event) => {
// Get the event from parent
}
}));
return (
[...]
);
});
Child.displayName = "Child";
// React >= 19
const Child = ({ ref, ...props }) => {
useImperativeHandle(ref, () => ({
doSomething: (event) => {
// Get the event from parent
}
}));
return (
[...]
);
};
I decided to use the solution provided by Francis Malloch on this post1:
class Parent extends React.Component {
childCallables = null;
setChildCallables = (callables) => {
this.childCallables = callables;
}
handleKeyDown = (event) => {
// Call the child function doSomething()
this.childCallables.doSomething(event);
}
render() {
return (
<input
type="text"
onKeyDown={this.handleKeyDown}
>
<Child setCallables={this.setChildCallables} />
)
}
}
class Child extends React.Component {
componentDidMount() {
this.props.setCallables({
doSomething: this.doSomething
});
}
doSomething = (event) => {
// Get the event from parent
}
render() {
return (
[...]
)
}
}
Basically, I'm using a props to store the child's methods I need to access from the parent. The methods are saved in the props just after the child component is mounted.
1. Since it is an answer to a completely different question, I don't think marking this one as a duplicate would make sense.