Cloning children with new props
You can use React.Children to iterate over the children, and then clone each element with new props (shallow merged) using React.cloneElement.
See the code comment why I don't recommend this approach.
Using cloneElement is uncommon and can lead to fragile code. See common alternatives. source: react.dev
const Child = ({ childName, sayHello }) => (
<button onClick={() => sayHello(childName)}>{childName}</button>
);
function Parent({ children }) {
// We pass this `sayHello` function into the child elements.
function sayHello(childName) {
console.log(`Hello from ${childName} the child`);
}
const childrenWithProps = React.Children.map(children, child => {
// Checking isValidElement is the safe way and avoids a
// typescript error too.
if (React.isValidElement(child)) {
return React.cloneElement(child, { sayHello });
}
return child;
});
return <div>{childrenWithProps}</div>
}
function App() {
// This approach is less type-safe and Typescript friendly since it
// looks like you're trying to render `Child` without `sayHello`.
// It's also confusing to readers of this code.
return (
<Parent>
<Child childName="Billy" />
<Child childName="Bob" />
</Parent>
);
}
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="container"></div>
Calling children as a function
Alternatively, you can pass props to children via render props. In this approach, the children (which can be children or any other prop name) is a function which can accept any arguments you want to pass and returns the actual children:
const Child = ({ childName, sayHello }) => (
<button onClick={() => sayHello(childName)}>{childName}</button>
);
function Parent({ children }) {
function sayHello(childName) {
console.log(`Hello from ${childName} the child`);
}
// `children` of Parent must be a function
// which returns the actual children. We can pass
// it args to then pass into them as props (in this
// case we pass `sayHello`).
return <div>{children(sayHello)}</div>
}
function App() {
// sayHello is the arg we passed in Parent, which
// we now pass through to Child.
return (
<Parent>
{(sayHello) => (
<>
<Child childName="Billy" sayHello={sayHello} />
<Child childName="Bob" sayHello={sayHello} />
</>
)}
</Parent>
);
}
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="container"></div>
Answer from nanobar on Stack OverflowHow to pass props to {this.props.children} - javascript
reactjs - passing props form child to parent component in react - Stack Overflow
Can we pass props from Parent to Child component in React, and set the props as state of child component?
reactjs - Passing state from parent to child functional React Component - Stack Overflow
Videos
Cloning children with new props
You can use React.Children to iterate over the children, and then clone each element with new props (shallow merged) using React.cloneElement.
See the code comment why I don't recommend this approach.
Using cloneElement is uncommon and can lead to fragile code. See common alternatives. source: react.dev
const Child = ({ childName, sayHello }) => (
<button onClick={() => sayHello(childName)}>{childName}</button>
);
function Parent({ children }) {
// We pass this `sayHello` function into the child elements.
function sayHello(childName) {
console.log(`Hello from ${childName} the child`);
}
const childrenWithProps = React.Children.map(children, child => {
// Checking isValidElement is the safe way and avoids a
// typescript error too.
if (React.isValidElement(child)) {
return React.cloneElement(child, { sayHello });
}
return child;
});
return <div>{childrenWithProps}</div>
}
function App() {
// This approach is less type-safe and Typescript friendly since it
// looks like you're trying to render `Child` without `sayHello`.
// It's also confusing to readers of this code.
return (
<Parent>
<Child childName="Billy" />
<Child childName="Bob" />
</Parent>
);
}
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="container"></div>
Calling children as a function
Alternatively, you can pass props to children via render props. In this approach, the children (which can be children or any other prop name) is a function which can accept any arguments you want to pass and returns the actual children:
const Child = ({ childName, sayHello }) => (
<button onClick={() => sayHello(childName)}>{childName}</button>
);
function Parent({ children }) {
function sayHello(childName) {
console.log(`Hello from ${childName} the child`);
}
// `children` of Parent must be a function
// which returns the actual children. We can pass
// it args to then pass into them as props (in this
// case we pass `sayHello`).
return <div>{children(sayHello)}</div>
}
function App() {
// sayHello is the arg we passed in Parent, which
// we now pass through to Child.
return (
<Parent>
{(sayHello) => (
<>
<Child childName="Billy" sayHello={sayHello} />
<Child childName="Bob" sayHello={sayHello} />
</>
)}
</Parent>
);
}
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="container"></div>
For a slightly cleaner way to do it, try:
<div>
{React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>
Edit: To use with multiple individual children (the child must itself be a component) you can do. Tested in 16.8.6
<div>
{React.cloneElement(this.props.children[0], { loggedIn: true, testPropB: true })}
{React.cloneElement(this.props.children[1], { loggedIn: true, testPropA: false })}
</div>
You can't pass props from child to parent in React, it's only one way (from parent to child).
You should either:
- Put the state in the parent component and manipulate it from the child component by passing the setter function in the props
- Use something like Redux Toolkit to create a global state that all components can have access to
For the newcomers here do it so:
Parent component:
import Child from './Child';
export default function Parent() {
const data_from_child = (data) => {
console.log(data); // or set the data to a state
}
return (
<Child setter={data_from_child} /> //pass the function to the child
)
}
Child component:
export default function Child ({setter}) {
setter('Data from Child');
return (<></>)
}
Here is simple sandbox where you can see how to pass state from parent to child component, and how to change parent state inside child component -> https://codesandbox.io/s/autumn-glitter-k9b1jc?file=/src/App.js
First you should not pass states like this, you can use global state management for it. But by this way of passing state you can do it as props like:
<ChildComponent state={state.loggedIn}/>
and
export const ChildComponent = ({state}) => {
...
}
Edit: see the end examples for ES6 updated examples.
This answer simply handle the case of direct parent-child relationship. When parent and child have potentially a lot of intermediaries, check this answer.
Other solutions are missing the point
While they still work fine, other answers are missing something very important.
Is there not a simple way to pass a child's props to its parent using events, in React.js?
The parent already has that child prop!: if the child has a prop, then it is because its parent provided that prop to the child! Why do you want the child to pass back the prop to the parent, while the parent obviously already has that prop?
Better implementation
Child: it really does not have to be more complicated than that.
var Child = React.createClass({
render: function () {
return <button onClick={this.props.onClick}>{this.props.text}</button>;
},
});
Parent with single child: using the value it passes to the child
var Parent = React.createClass({
getInitialState: function() {
return {childText: "Click me! (parent prop)"};
},
render: function () {
return (
<Child onClick={this.handleChildClick} text={this.state.childText}/>
);
},
handleChildClick: function(event) {
// You can access the prop you pass to the children
// because you already have it!
// Here you have it in state but it could also be
// in props, coming from another parent.
alert("The Child button text is: " + this.state.childText);
// You can also access the target of the click here
// if you want to do some magic stuff
alert("The Child HTML is: " + event.target.outerHTML);
}
});
JsFiddle
Parent with list of children: you still have everything you need on the parent and don't need to make the child more complicated.
var Parent = React.createClass({
getInitialState: function() {
return {childrenData: [
{childText: "Click me 1!", childNumber: 1},
{childText: "Click me 2!", childNumber: 2}
]};
},
render: function () {
var children = this.state.childrenData.map(function(childData,childIndex) {
return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
}.bind(this));
return <div>{children}</div>;
},
handleChildClick: function(childData,event) {
alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
alert("The Child HTML is: " + event.target.outerHTML);
}
});
JsFiddle
It is also possible to use this.handleChildClick.bind(null,childIndex) and then use this.state.childrenData[childIndex]
Note we are binding with a null context because otherwise React issues a warning related to its autobinding system. Using null means you don't want to change the function context. See also.
About encapsulation and coupling in other answers
This is for me a bad idea in term of coupling and encapsulation:
var Parent = React.createClass({
handleClick: function(childComponent) {
// using childComponent.props
// using childComponent.refs.button
// or anything else using childComponent
},
render: function() {
<Child onClick={this.handleClick} />
}
});
Using props: As I explained above, you already have the props in the parent so it's useless to pass the whole child component to access props.
Using refs: You already have the click target in the event, and in most case this is enough. Additionnally, you could have used a ref directly on the child:
<Child ref="theChild" .../>
And access the DOM node in the parent with
React.findDOMNode(this.refs.theChild)
For more advanced cases where you want to access multiple refs of the child in the parent, the child could pass all the dom nodes directly in the callback.
The component has an interface (props) and the parent should not assume anything about the inner working of the child, including its inner DOM structure or which DOM nodes it declares refs for. A parent using a ref of a child means that you tightly couple the 2 components.
To illustrate the issue, I'll take this quote about the Shadow DOM, that is used inside browsers to render things like sliders, scrollbars, video players...:
They created a boundary between what you, the Web developer can reach and what’s considered implementation details, thus inaccessible to you. The browser however, can traipse across this boundary at will. With this boundary in place, they were able to build all HTML elements using the same good-old Web technologies, out of the divs and spans just like you would.
The problem is that if you let the child implementation details leak into the parent, you make it very hard to refactor the child without affecting the parent. This means as a library author (or as a browser editor with Shadow DOM) this is very dangerous because you let the client access too much, making it very hard to upgrade code without breaking retrocompatibility.
If Chrome had implemented its scrollbar letting the client access the inner dom nodes of that scrollbar, this means that the client may have the possibility to simply break that scrollbar, and that apps would break more easily when Chrome perform its auto-update after refactoring the scrollbar... Instead, they only give access to some safe things like customizing some parts of the scrollbar with CSS.
About using anything else
Passing the whole component in the callback is dangerous and may lead novice developers to do very weird things like calling childComponent.setState(...) or childComponent.forceUpdate(), or assigning it new variables, inside the parent, making the whole app much harder to reason about.
Edit: ES6 examples
As many people now use ES6, here are the same examples for ES6 syntax
The child can be very simple:
const Child = ({
onClick,
text
}) => (
<button onClick={onClick}>
{text}
</button>
)
The parent can be either a class (and it can eventually manage the state itself, but I'm passing it as props here:
class Parent1 extends React.Component {
handleChildClick(childData,event) {
alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
alert("The Child HTML is: " + event.target.outerHTML);
}
render() {
return (
<div>
{this.props.childrenData.map(child => (
<Child
key={child.childNumber}
text={child.childText}
onClick={e => this.handleChildClick(child,e)}
/>
))}
</div>
);
}
}
But it can also be simplified if it does not need to manage state:
const Parent2 = ({childrenData}) => (
<div>
{childrenData.map(child => (
<Child
key={child.childNumber}
text={child.childText}
onClick={e => {
alert("The Child button data is: " + child.childText + " - " + child.childNumber);
alert("The Child HTML is: " + e.target.outerHTML);
}}
/>
))}
</div>
)
JsFiddle
PERF WARNING (apply to ES5/ES6): if you are using PureComponent or shouldComponentUpdate, the above implementations will not be optimized by default because using onClick={e => doSomething()}, or binding directly during the render phase, because it will create a new function everytime the parent renders. If this is a perf bottleneck in your app, you can pass the data to the children, and reinject it inside "stable" callback (set on the parent class, and binded to this in class constructor) so that PureComponent optimization can kick in, or you can implement your own shouldComponentUpdate and ignore the callback in the props comparison check.
You can also use Recompose library, which provide higher order components to achieve fine-tuned optimisations:
// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}
// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)
// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)
In this case you could optimize the Child component by using:
const OptimizedChild = onlyUpdateForKeys(['text'])(Child)
Update (9/1/15): The OP has made this question a bit of a moving target. It’s been updated again. So, I feel responsible to update my reply.
First, an answer to your provided example:
Yes, this is possible.
You can solve this by updating Child’s onClick to be this.props.onClick.bind(null, this):
var Child = React.createClass({
render: function () {
return <a onClick={this.props.onClick.bind(null, this)}>Click me</a>;
}
});
The event handler in your Parent can then access the component and event like so:
onClick: function (component, event) {
// console.log(component, event);
},
JSBin snapshot
But the question itself is misleading
Parent already knows Child’s props.
This isn’t clear in the provided example because no props are actually being provided. This sample code might better support the question being asked:
var Child = React.createClass({
render: function () {
return <a onClick={this.props.onClick}> {this.props.text} </a>;
}
});
var Parent = React.createClass({
getInitialState: function () {
return { text: "Click here" };
},
onClick: function (event) {
// event.component.props ?why is this not available?
},
render: function() {
return <Child onClick={this.onClick} text={this.state.text} />;
}
});
It becomes much clearer in this example that you already know what the props of Child are.
JSBin snapshot
If it’s truly about using a Child’s props…
If it’s truly about using a Child’s props, you can avoid any hookup with Child altogether.
JSX has a spread attributes API I often use on components like Child. It takes all the props and applies them to a component. Child would look like this:
var Child = React.createClass({
render: function () {
return <a {...this.props}> {this.props.text} </a>;
}
});
Allowing you to use the values directly in the Parent:
var Parent = React.createClass({
getInitialState: function () {
return { text: "Click here" };
},
onClick: function (text) {
alert(text);
},
render: function() {
return <Child onClick={this.onClick.bind(null, this.state.text)} text={this.state.text} />;
}
});
JSBin snapshot
And there's no additional configuration required as you hookup additional Child components
var Parent = React.createClass({
getInitialState: function () {
return {
text: "Click here",
text2: "No, Click here",
};
},
onClick: function (text) {
alert(text);
},
render: function() {
return <div>
<Child onClick={this.onClick.bind(null, this.state.text)} text={this.state.text} />
<Child onClick={this.onClick.bind(null, this.state.text2)} text={this.state.text2} />
</div>;
}
});
JSBin snapshot
But I suspect that’s not your actual use case. So let’s dig further…
A robust practical example
The generic nature of the provided example is a hard to talk about. I’ve created a component that demonstrations a practical use for the question above, implemented in a very Reacty way:
DTServiceCalculator working example
DTServiceCalculator repo
This component is a simple service calculator. You provide it with a list of services (with names and prices) and it will calculate a total the selected prices.
Children are blissfully ignorant
ServiceItem is the child-component in this example. It doesn’t have many opinions about the outside world. It requires a few props, one of which is a function to be called when clicked.
<div onClick={this.props.handleClick.bind(this.props.index)} />
It does nothing but to call the provided handleClick callback with the provided index[source].
Parents are Children
DTServicesCalculator is the parent-component is this example. It’s also a child. Let’s look.
DTServiceCalculator creates a list of child-component (ServiceItems) and provides them with props [source]. It’s the parent-component of ServiceItem but it`s the child-component of the component passing it the list. It doesn't own the data. So it again delegates handling of the component to its parent-component source
<ServiceItem chosen={chosen} index={i} key={id} price={price} name={name} onSelect={this.props.handleServiceItem} />
handleServiceItem captures the index, passed from the child, and provides it to its parent [source]
handleServiceClick (index) {
this.props.onSelect(index);
}
Owners know everything
The concept of “Ownership” is an important one in React. I recommend reading more about it here.
In the example I’ve shown, I keep delegating handling of an event up the component tree until we get to the component that owns the state.
When we finally get there, we handle the state selection/deselection like so [source]:
handleSelect (index) {
let services = […this.state.services];
services[index].chosen = (services[index].chosen) ? false : true;
this.setState({ services: services });
}
Conclusion
Try keeping your outer-most components as opaque as possible. Strive to make sure that they have very few preferences about how a parent-component might choose to implement them.
Keep aware of who owns the data you are manipulating. In most cases, you will need to delegate event handling up the tree to the component that owns that state.
Aside: The Flux pattern is a good way to reduce this type of necessary hookup in apps.