There are, I think, a few problems with your example that make it more complex than necessary: the Name component is a fuzzy abstraction, and the Name component knows too much. (In fact, they are a bit intertwined.)
Before solving these problems, I want to take a short detour to discuss my approach to component design. I find that mixing downstream and upstream approaches is very useful for building React applications. Use from top to bottom helps determine which components to create, starting with the idea of the component and determining what its subcomponents are, and then identifying the subcomponents of the subcomponents, ad nauseam. After defining the components, the transition time to the approach is from bottom to top, where you take the most basic component (no new subcomponents needed to create it), and create it as stand-alone and independent, and then select the next basic component and implement it, and repeat until completion.
When you implement a component, you can think of the incoming details as an API for use by other components, and you want to concentrate as best as possible on what functionality your component should provide.
So back to the problems in your example.
Firstly, your Name component is a small abstraction. (Yes, I know that this is just an arbitrary example, but bear with me.) The component presents onClick as part of its API (since it is needed as a support). This is problematic because it talks about the components that want to use it: "Hey, I have a button here!" This is fine with your current implementation of Name, but what happens when you need to change Name to have different behavior? onClick no longer makes sense, and if you want to change that name, then that will change throughout the rest of your code. Instead, you might consider using the name "update", which seems like a reasonable operation for the Name component, to hide the fact that it contains a button inside. Of course, this can be seen as the “take care when naming things” argument, but I think that good naming is a valuable tool in creating components that are easy to use and easy to modify later.
Another problem is that the Name component knows too much about the parent implementation, which makes it difficult to use in other components later. Instead of running "bind" in the Name component, suppose that the owner container passes a function that takes one parameter - newName. Inside the name component, you only need to call this function with the new name you want. How this affects any other condition is not a concern for names, and you have effectively put off a solution to this problem until you have another choice. Then the Name component looks like this:
var Name = React.createClass({ render: function() { return <button onClick={() => this.props.update('John')}>{this.props.name}</button>; } });
Note that you no longer need an identifier; you just accept and update the name.
Since you really need to worry about updating names in the NameContainer component (from where the data is), you can worry about it. To avoid enumerating all identifiers, create a function that takes a name object and a new name, and then binds each name object to a function, similar to what you had in the Name component. (What remains is a function that takes a single parameter newName, which we can use as an update function for Name!). The code looks like this:
var NameContainer = React.createClass({ getInitialState: function() { return { names: [ { id: 1, name: 'Fred' }, { id: 2, name: 'George' } ] }; }, update: function(obj, newName) { obj.name = newName; this.setState({ names: this.state.names }); }, render: function() { var children = this.state.names.map(function(obj){ return <Name key={obj.id} name={obj.name} update={this.update.bind(null, obj)} />; }, this); return ( <div> {children} </div> ); } });
It really simplifies your components, and now Name can be used in a wider context. I updated your sample with the changes you described here , and for the kicks, I added another implementation of Name here . NameContainer did not need to be changed since the Name API has not changed, even though the name implementation is different from two.
Using this bottom-up approach helps you cope with your concern about transferring props through a chain of subcomponents. When you create and test a component, you only need to take care of the specific problem you are dealing with with this component; ensuring that you pass on the requisites to your subcomponents. Because you focus on a very specific issue, you are less likely to miss an important piece of data.
You can look at it and still wonder, “Why is it so difficult?” Consider an application in which you want to display the same data in different ways (for example, a graph and the corresponding data table). React gives you the ability to exchange data between components and synchronize them. If you saved all the data and processed it as locally as possible (as much as possible, as many as possible subcomponents), you will have to implement synchronization between the components yourself. By putting the data as high as possible in the component chain, you make it (efficiently) global for those components, and React may worry about the rest of the details. You worry about data transfer and how data is displayed, and React takes care of everyone else.
As a final note, if your application continues to grow in complexity, you can consider Flux . This is an architectural model that helps manage the complexity of your application. This is not a panacea, but I found it to be very good when I used it in some rather complex applications.