React composition - How to call parent method
Solution 1:
I recently had to do something similar and, inspired by this post, I ended up with:
const WrapperComponent = ({ children }) => {
const myFunc = React.useCallback(() => {
// ...
}, []);
return React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { onClick: myFunc });
}
});
}
[edit] a working demo:
The following snippet demonstrate how the above approach could be used to read a child prop from the wrapper/parent component.
Please be aware that it might take a few seconds for the snippet to load and run; I did not investigate the reason for this, as it is out of the scope for the question.
const App = () => {
return (
<div>
<h1>MyApp</h1>
<WrapperComponent>
<button id='btn1'>btn1</button>
<button id='btn2'>btn2</button>
<button id='btn3'>btn3</button>
<div className='fakeBtn' id='div1'>div1</div>
</WrapperComponent>
</div>
);
}
const WrapperComponent = ({ children }) => {
const [clickedChildId, setClickedChildId] = React.useState();
const myFunc = React.useCallback((id) => {
setClickedChildId(id)
}, [setClickedChildId]);
React.useEffect(() => {
clickedChildId && console.log(`the clicked child ID is ${clickedChildId}`);
}, [clickedChildId]);
return React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { onClick: () => myFunc(child.props.id) });
}
});
}
ReactDOM.render(<App />, document.querySelector('#mountNode'))
div.fakeBtn {
background-color: #cdf;
padding: 5px;
margin: 3px 0;
border: 1px solid #ccc;
border-radius: 2px;
}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id='mountNode'></div>
Solution 2:
You can do it by cloning the children, and giving it the props that you want:
React.cloneElement(children, {calledByChild})
This way, you add the function calledByChild
to the children, so you can call it from the children component.
It could look like this:
const Parent = ({ children }) => {
const func = () => console.log("click in Parent");
return (
<>
<div>children</div>
{cloneElement(children, {func})}
</>
);
};
const Children = ({func}) => {
return <button onClick={func}>Click</button>;
};
Take a look at this article