How can I listen to an event that occurs in a child of child of child… component?
In the example bellow, how can I handle to the “ChildLevel2 – button – onClick” event in the “MainComponent” ?
function MainComponent() {
return (
<>
<ChildLevel1/>
</>
);
}
function ChildLevel1() {
return (
<>
<ChildLevel2/>
</>
);
}
function ChildLevel2() {
return (
<>
<button>Click-me!</button>
</>
);
}
3
Here are some possible ways
1. Passing down the function as a prop – This can be a headache if you have to pass it down too deep. Just 2 levels is just fine I guess
function MainComponent(){
const handleButtonClick = (data) => {
console.log('from child2', data);
};
return (
<React.Fragment>
<ChildLevel1 onButtonClick={handleButtonClick}/>
</React.Fragment>
);
};
function ChildLevel1({onButtonClick}){
return (
<React.Fragment>
<ChildLevel2 onButtonClick={onButtonClick}/>
</React.Fragment>
);
};
function ChildLevel2({onButtonClick}){
return (
<React.Fragment>
<button onClick={() => onButtonClick('passed data')}>Click-me!</button>
</React.Fragment>
);
}
ReactDOM.render(<MainComponent />, document.getElementById("app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="app"></div>
2. Using Context API. createContext , useContext. Like a centralized state so works better if too deeply nested you won’t have to keep passing as props
const ButtonClickContext = React.createContext(null);
function MainComponent(){
const handleButtonClick = (data) => {
console.log('from child2', data);
};
return (
<ButtonClickContext.Provider value={handleButtonClick}>
<React.Fragment>
<ChildLevel1/>
</React.Fragment>
</ButtonClickContext.Provider>
);
};
function ChildLevel1(){
return (
<React.Fragment>
<ChildLevel2/>
</React.Fragment>
);
};
function ChildLevel2(){
const onButtonClick = React.useContext(ButtonClickContext);
return (
<React.Fragment>
<button onClick={() => onButtonClick('passed data')}>Click-me!</button>
</React.Fragment>
);
}
ReactDOM.render(<MainComponent />, document.getElementById("app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="app"></div>
to show an example of what the comments suggest:
const MainComponent = () => {
const handleNestedEvent = (e) => {
console.log('handling event in top level component', e);
}
return (
<ChildLevel1 onNestedEvent={handleNestedEvent}/>
)
}
const ChildLevel1 = ({ onNestedEvent }) => {
return <ChildLevel2 onNestedEvent={onNestedEvent}/>
}
const ChildLevel2 = ({ onNestedEvent }) => {
return <button onClick={onNestedEvent}>Click Me</button>
}
could instead useContext: react context docs
or redux: react redux docs