Seleccionar página

How to build nested React components

Complex React components

React doesn’t force you to follow a specific component structure or hierarchy. We could build our whole app in a single React component and render all the content together in the same function. However, following this approach would not be the best choice as we would not be taking all the advantage of building reusable and modular components. Instead of having all our DOM elements living in the same React component it is better to break it down into multiple components.

Nested components example

In this example we are going to build an application based on child/parent relationship. The parents will be the main containers where all their children will be instantiated. In the following picture you can notice the similarity between React and DOM tree:

React components tree

Main container

As we have said before, we’ll follow a child/parent relationship between components. This means that at the top level we’ll have the main container that will start creating our component tree. There is no limit about the number of nested components (children) that a component could have and about the depth of our component tree.

nested react component tree

The code below shows us the render method of the App component. The most important part of this code is how to include the React components. We will use them like regular HTML elements:

<br />class App extends React.Component {</p>
<p>render() {<br />return (<br />&amp;amp;lt;div&amp;amp;gt;<br />&amp;amp;lt;h1&amp;amp;gt;Filterable React List&amp;amp;lt;/h1&amp;amp;gt;<br />&amp;amp;lt;SearchBar /&amp;amp;gt;<br />&amp;amp;lt;ContactTable /&amp;amp;gt;<br />&amp;amp;lt;/div&amp;amp;gt;<br />);<br />}<br />}</p>
<p>

Child components

In this case we have 2 nested components: SearchBar and ContactTable. Notice that the last one will also act as the parent of multiple ContactRow components.

</p>
<p>class ContactTable extends React.Component {<br />return (<br />&amp;amp;lt;table className='table'&amp;amp;gt;<br />&amp;amp;lt;thead&amp;amp;gt;<br />&amp;amp;lt;tr&amp;amp;gt;<br />&amp;amp;lt;th&amp;amp;gt;Name&amp;amp;lt;/th&amp;amp;gt;<br />&amp;amp;lt;th&amp;amp;gt;Phone&amp;amp;lt;/th&amp;amp;gt;<br />&amp;amp;lt;th&amp;amp;gt;Email&amp;amp;lt;/th&amp;amp;gt;<br />&amp;amp;lt;/tr&amp;amp;gt;<br />&amp;amp;lt;/thead&amp;amp;gt;<br />&amp;amp;lt;tbody&amp;amp;gt;<br />&amp;amp;lt;ContactRow /&amp;amp;gt;&amp;amp;lt;ContactRow /&amp;amp;gt;&amp;amp;lt;/tbody&amp;amp;gt;<br />&amp;amp;lt;/table&amp;amp;gt;<br />);<br />}<br />}</p>
<p>class ContactRow extends React.Component {<br />render() {<br />return (<br />&amp;amp;lt;tr&amp;amp;gt;<br />&amp;amp;lt;td&amp;amp;gt;John Larsson&amp;amp;lt;/td&amp;amp;gt;<br />&amp;amp;lt;td&amp;amp;gt;555-332-157&amp;amp;lt;/td&amp;amp;gt;<br />&amp;amp;lt;td&amp;amp;gt;larsson@gmail.com&amp;amp;lt;/td&amp;amp;gt;<br />&amp;amp;lt;/tr&amp;amp;gt;<br />);<br />}<br />}</p>
<p>class SearchBar extends React.Component {<br />render() {<br />return (<br />&amp;amp;lt;form&amp;amp;gt;<br />&amp;amp;lt;input<br />className=&amp;quot;form-control&amp;quot;<br />type=&amp;quot;text&amp;quot;<br />placeholder=&amp;quot;Search...&amp;quot;<br />/&amp;amp;gt;<br />&amp;amp;lt;/form&amp;amp;gt;<br />);<br />}<br />}</p>
<p>

Final step: rendering our React app

Finally we only have to call RenderDOM.render() method passing the main component as the first parameter and the DOM tree element where we want to mount our app as the second parameter:

<br />ReactDOM.render(<br />&amp;amp;lt;App /&amp;amp;gt;,<br />document.getElementById('container')<br />);<br />

Dynamic components

One of the basic features when building web applications is the dynamic creation and modification of the DOM tree (React components in this case). This means that depending on the data of the moment, we’ll need to build a different set of components. Typical scenarios are lists or tables that are built using the information of an array of objects.

This can be easily done using the props object to pass the information from the parent to the children. Let’s show how to do this modifying the previouse example.

</p>
<p>class App extends React.Component {<br />constructor(props) {<br />super(props);<br />const contacts = [<br />{name: 'Tom Jackson', phone: '555-444-333', email: 'tom@gmail.com'},<br />{name: 'Mike James', phone: '555-777-888', email: 'mikejames@gmail.com'},<br />{name: 'Janet Larson', phone: '555-222-111', email: 'janetlarson@gmail.com'},<br />{name: 'Clark Thompson', phone: '555-444-333', email: 'clark123@gmail.com'},<br />{name: 'Emma Page', phone: '555-444-333', email: 'emma1page@gmail.com'},<br />];</p>
<p>}</p>
<p>render() {<br />return (<br />&amp;amp;lt;div&amp;amp;gt;<br />&amp;amp;lt;h1&amp;amp;gt;Filterable React List&amp;amp;lt;/h1&amp;amp;gt;<br />&amp;amp;lt;SearchBar /&amp;amp;gt;<br />&amp;amp;lt;ContactTable contacts={this.props.contacts}<br />/&amp;amp;gt;<br />&amp;amp;lt;/div&amp;amp;gt;<br />);<br />}<br />}</p>
<p>class ContactRow extends React.Component {<br />render() {<br />return (<br />&amp;amp;lt;tr&amp;amp;gt;<br />&amp;amp;lt;td&amp;amp;gt;{this.props.contact.name}&amp;amp;lt;/td&amp;amp;gt;<br />&amp;amp;lt;td&amp;amp;gt;{this.props.contact.phone}&amp;amp;lt;/td&amp;amp;gt;<br />&amp;amp;lt;td&amp;amp;gt;{this.props.contact.email}&amp;amp;lt;/td&amp;amp;gt;<br />&amp;amp;lt;/tr&amp;amp;gt;<br />);<br />}<br />}</p>
<p>class ContactTable extends React.Component {<br />render() {<br />var rows = [];<br />this.props.contacts.map((contact) =&amp;amp;gt; rows.push(&amp;amp;lt;ContactRow contact={contact} /&amp;amp;gt;);<br />});</p>
<p>return (<br />&amp;amp;lt;table className='table'&amp;amp;gt;<br />&amp;amp;lt;thead&amp;amp;gt;<br />&amp;amp;lt;tr&amp;amp;gt;<br />&amp;amp;lt;th&amp;amp;gt;Name&amp;amp;lt;/th&amp;amp;gt;<br />&amp;amp;lt;th&amp;amp;gt;Phone&amp;amp;lt;/th&amp;amp;gt;<br />&amp;amp;lt;th&amp;amp;gt;Email&amp;amp;lt;/th&amp;amp;gt;<br />&amp;amp;lt;/tr&amp;amp;gt;<br />&amp;amp;lt;/thead&amp;amp;gt;<br />&amp;amp;lt;tbody&amp;amp;gt;{rows}&amp;amp;lt;/tbody&amp;amp;gt;<br />&amp;amp;lt;/table&amp;amp;gt;<br />);<br />}<br />}</p>
<p>

As you can see in the example above, the App component passes to the ContactTable the array of contacts as a property. Then, the ContactTable component iterates through the array creating child components and passing them the object as a property. Finally, each ContactRow will access to the information of the given object through the props object.

Handling Events with nested components

As we said in the React tutorial for beginners, we know that events can be handled by React components in a similar way than in regular DOM events. But, what happens if we want to notify the parent of the children? For this purpose we will use the props object to pass the parent handler to the child:

See the Pen Handle Events in React by Jon Vadillo (@jonvadillo) on CodePen.light

A typical scenario is when the event handled by the child (e.g. a click on a button for refreshing data) produces a change on the state managed by the parent and therefore the components are rendered again (e.g. for showing updated data from the server):

  1. Click event happens in the child component and handled by the method defined in the onChange.
  2. Child component calls the parents handler via props object
  3. The parent handles the event, and updates the state (using provided setState() method) with new information.
  4. State change produces a re-rendering of the parent and children. The latest will receive the new information through props object.

Conclusion

In this React tutorial you have learnt how to build nested React components and how to handle events. If you have any question about the article or want to comment something about the post I’ll be really happy to hearing from you. Remember that you can learn the React basics in my previous React tutorial where you can learn the basics of React.

Happy coding!