Problem
Isn’t there a simple method in React.js to pass a child’s props to its parent via events?
var Child = React.createClass({
render: function() {
<a onClick={this.props.onClick}>Click me</a>
}
});
var Parent = React.createClass({
onClick: function(event) {
// event.component.props ?why is this not available?
},
render: function() {
<Child onClick={this.onClick} />
}
});
I know you can pass an input’s value using controlled components, but it’d be wonderful to pass the full shebang. Occasionally, the child component contains data that you’d rather not have to dig up.
Perhaps there’s a way to bind the component to the event?
After over a year of using React and being inspired by Sebastien Lorber’s response, I’ve come to the conclusion that giving child components as arguments to methods in parents is neither the React way nor a good concept. I’ve changed the response.
Asked by KendallB
Solution #1
Edit: see the end examples for ES6 updated examples.
This response only addresses the situation of a direct parent-child relationship. Check this option if there are a lot of intermediates between the parent and the child.
While they still function properly, other responses are missing something crucial.
The parent already has that child’s prop! If the youngster has a prop, it’s because the child’s parent gave it to them! Why do you want the child to return the prop to the parent when you know the parent already has it?
It doesn’t have to be any more complicated than that, kid.
var Child = React.createClass({
render: function () {
return <button onClick={this.props.onClick}>{this.props.text}</button>;
},
});
Using the value it passes to the child as a parent with a single 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
This is also a viable option. After that, use this.state.handleChildClick.bind(null,childIndex) .childrenData[childIndex]
It’s worth noting that we’re binding with a null context because React would otherwise send a warning about its autobinding system. When you use null, you’re indicating that you don’t want to change the function context. Also see.
In terms of coupling and encapsulation, I believe this is a horrible idea:
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 previously stated, you already have the props in the parent, so passing the entire child component to access props is pointless.
Using refs: You already have the click target in the event, which should suffice in most cases. Furthermore, you could have used a direct ref on the child:
<Child ref="theChild" .../>
And you can get to the parent’s DOM node with
React.findDOMNode(this.refs.theChild)
In more advanced scenarios, the child might transmit all the dom nodes directly in the callback if you want to access numerous references of the child in the parent.
The parent should not presume anything about the inner workings of the child, including its inner DOM structure or which DOM nodes it declares refs for, because the component has an interface (props). When you use a kid as a ref, you’re strongly coupling the two components.
I’ll use this comment on the Shadow DOM, which is used inside browsers to show features like sliders, scrollbars, and video players, to highlight the problem:
The difficulty is that leaking child implementation details into the parent makes refactoring the child difficult without harming the parent. As a library creator (or a browser editor using Shadow DOM), this is extremely risky because you’re giving the client much too much access, making it difficult to change code without damaging retrocompatibility.
If Chrome had constructed its scrollbar in such a way that the client could access the scrollbar’s inner dom nodes, this would mean that the client could simply break the scrollbar, and therefore apps would be more likely to break when Chrome performed its auto-update after restructuring the scrollbar… Instead, they limit access to only a few secure options, such as using CSS to customize particular sections of the scrollbar.
Concerning the use of anything else
Passing the entire component in the callback is risky, as it may lead inexperienced developers to do strange things inside the parent, such as calling childComponent.setState(…) or childComponent.forceUpdate(), or assigning it new variables, making the entire app much more difficult to reason about.
Edit: ES6 examples
Given the widespread adoption of ES6, here are the same examples for ES6 syntax.
The child can be extremely straightforward:
const Child = ({
onClick,
text
}) => (
<button onClick={onClick}>
{text}
</button>
)
The parent can be a class (which can eventually manage the state itself, but I’m sending it as props here: ) or a variable.
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>
);
}
}
However, if it does not need to manage state, it can be simplified:
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 (ES5/ES6): If you use PureComponent or shouldComponentUpdate, the above implementations will not be optimized by default since using onClick=e => doSomething(), or binding directly during the render phase, would construct a new function every time the parent renders. If this is a performance bottleneck in your app, you can pass the data to the children and reinject it inside the “stable” callback (set on the parent class and bound to this in the class constructor) for PureComponent optimization, or you can implement your own shouldComponentUpdate and ignore the callback in the props comparison check.
To obtain fine-tuned optimisations, you can also use the Recompose library, which provides higher order components:
// 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 scenario, you might make the Child component more efficient by using:
const OptimizedChild = onlyUpdateForKeys(['text'])(Child)
Answered by Sebastien Lorber
Solution #2
Update (9/1/15): The OP has moved the goalposts on this question. It’s been updated once more. As a result, I feel obligated to revise my response.
Yes, this is a viable option.
This can be fixed by changing Child’s onClick to this. props.onClick.bind(null, this): props.onClick.bind(null, this): props.onClick.
var Child = React.createClass({
render: function () {
return <a onClick={this.props.onClick.bind(null, this)}>Click me</a>;
}
});
The component and event can then be accessed by the event handler in your Parent as follows:
onClick: function (component, event) {
// console.log(component, event);
},
JSBin snapshot
Parent already knows Child’s props.
Because no props are provided in the presented example, this isn’t obvious. This sample code may provide a better answer to the question:
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} />;
}
});
In this example, it becomes evident that you already know what Child’s props are.
JSBin snapshot
You can avoid any hookup with Child if it’s actually about using a Child’s props.
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 in the Parent: directly
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
Additionally, as you connect new Child components, no additional setting is necessary.
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
However, I doubt that is your genuine use case. So let’s dig a little deeper…
The generic nature of the presented example makes it difficult to discuss. I’ve constructed a component that demonstrates a real application for the question above, using React:
DTServiceCalculator repo DTServiceCalculator working example
A simple service calculator is included in this component. You provide it a list of services (with names and pricing) and it calculates a total based on the prices you choose.
In this case, the child component is ServiceItem. It doesn’t have a lot of opinions about what’s going on in the world. It needs a few props, one of which is a function that will be called when the button is pressed.
It only performs one thing: it calls the supplied handle. With the index[source] specified, click callback.
In this example, the parent component is DTServicesCalculator. It’s also a youngster. Let’s have a peek.
DTServiceCalculator generates a list of child components (ServiceItems) and assigns props to them [source]. It’s the parent component of ServiceItem, yet it’s the child component of the list-passing component. It does not own the information. As a result, it delegated the component’s management to its parent-component source once more.
chosen=chosenServiceItem index={i} key={id} price={price} onSelect=this.props.handleServiceItem /> name=name onSelect=this.props.handleServiceItem />
handleServiceItem receives the index from the child and passes it on to the parent [source].
handleServiceClick (index) {
this.props.onSelect(index);
}
In React, the concept of “Ownership” is crucial. More information on it can be found here.
I keep delegating handling of an event up the component tree until we reach to the component that owns the state in the example I’ve presented.
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 });
}
Attempt to keep your outermost components as transparent as feasible. Make every effort to ensure that they have few preferences on how a parent-component might implement them.
Keep track of who owns the data you’re working with. In most circumstances, event handling must be delegated up the tree to the component that owns that state.
Aside: In apps, the Flux design is a nice technique to decrease the need for this type of hookup.
Answered by chantastic
Solution #3
There looks to be a straightforward solution. Consider the following:
var Child = React.createClass({
render: function() {
<a onClick={this.props.onClick.bind(null, this)}>Click me</a>
}
});
var Parent = React.createClass({
onClick: function(component, event) {
component.props // #=> {Object...}
},
render: function() {
<Child onClick={this.onClick} />
}
});
The key is to use the parent’s this.props.onClick event to call bind(null, this). The component and event arguments are now accepted by the onClick function. That, I believe, is the finest of all possible universes.
This was a horrible notion: allowing details about a child’s implementation to leak to the parent was never a smart idea. Take a look at Sebastien Lorber’s response.
Answered by KendallB
Solution #4
The issue is how to transmit an argument from a child component to the parent component. This example is simple to use and has been well tested:
//Child component
class Child extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div><button onClick={() => handleToUpdate('someVar')}>Push me</button></div>
)
}
}
//Parent component
class Parent extends React.Component {
constructor(props) {
super(props);
var handleToUpdate = this.handleToUpdate.bind(this);
}
handleToUpdate(someArg){
alert('We pass argument from Child to Parent: \n' + someArg);
}
render() {
var handleToUpdate = this.handleToUpdate;
return (<div>
<Child handleToUpdate = {handleToUpdate.bind(this)} />
</div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<Parent />,
document.querySelector("#demo")
);
}
Look at JSFIDDLE
Answered by Roman
Solution #5
Basically, props are used to convey and receive information between Child and Parent.
To add to all of the amazing responses, let me share a basic example of how to transmit values from a child component to a parent component in React.
App.js
class App extends React.Component {
constructor(){
super();
this.handleFilterUpdate = this.handleFilterUpdate.bind(this);
this.state={name:'igi'}
}
handleFilterUpdate(filterValue) {
this.setState({
name: filterValue
});
}
render() {
return (
<div>
<Header change={this.handleFilterUpdate} name={this.state.name} />
<p>{this.state.name}</p>
</div>
);
}
}
Header.js
class Header extends React.Component {
constructor(){
super();
this.state={
names: 'jessy'
}
}
Change(event) {
// this.props.change(this.state.names);
this.props.change('jessy');
}
render() {
return (
<button onClick={this.Change.bind(this)}>click</button>
);
}
}
Main.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
ReactDOM.render(<App />, document.getElementById('app'));
Thats it , now you can pass values from your client to the server.
Take a peek at the Header’s Change function. js
Change(event) {
// this.props.change(this.state.names);
this.props.change('jessy');
}
This is how you send values from the client to the server’s props.
Answered by Ignatius Andrew
Post is based on https://stackoverflow.com/questions/22639534/pass-props-to-parent-component-in-react-js