Nested Components - React JS

In React, Nested Components are React components that live as children within their container parent components. A parent component can be also a child of another component.

React JS Tutorials

Just a site created by a group of programmers who love react. We respect the original react documentation, but wrote this guide while learning react ourselves, and decided to share it. We hope our discoveries help someone else out there!

visual nested components diagram
Using Nested Components we can construct a truck axle and wheel management application. We're going to build one in this tutorial (see coding challenge below.)

Nested Components

Nested Components are exactly what the name implies. They are children nested inside parent components. They simply help us create more complex UI structures. For example, an alert component probably has another sub-component nested within it to indicate the actual number of alerts. A message box has an inner input element and a send button.

Nested components simplify complex applications. In this coding challenge, let's build a truck wheel manager application. I followed this modular approach to nest wheels inside axles, and nest axles within the truck frame (see image to the right.) Both wheels and axles could then be dynamically added or deleted from the UI, offering flexibility in defining different types of vehicles (trailer, semi, bus, etc.)

Understanding how props travel through nested components to the innermost children is important. Without redux (global component state management), one of the obvious things you might do is simply keep passing your props down the entire component hierarchy (through component constructors,) eventually landing at the element in which props data needs to be rendered.

Try not to think of nested react components as something more than what they really are. Nesting in one form or another, is a common pattern across most web development languages. In CSS you "cascade" (or nest) styles. In HTML, you nest tags. In React, you nest components. It's simply a modular way of thinking about your code.

Coding Challenge Ahead

Let's practice React Nested Components by creating a complex UI scaffold for truck axle and wheel management software.

First, Let's Practice Creating A Vanilla React Component

This tutorial will not make much sense without knowing how to create plain vanilla React components.

This subject is already covered in create basic react components tutorial on this site.

Recall how we usually create simple vanilla components in React:


    var Vehicle = React.createClass( { render: function() { return() } } );

That's just a boring React component. In a real-life coding situation, you must understand how to create useful components.

By using the ES6 syntax — in particular the class keyword — we make our code look a lot cleaner and easier to maintain later down the road. You might not think so at first, but things change as your react application's source code footprint starts to grow.

class Vehicle extends React.Component { constructor(props) { super(props); this.state = { axles: [], wheels: [] }; } // The render function shares the same scope with the constructor render() { // Use ES6 destructuring to get properties from state and props objects const { axles, wheels } = this.state; const { editable } = this.props; return (<Frame />) } }
class Vehicle extends React.Component {
    constructor(props) {
        super(props);
        this.state = { axles: [], wheels: [] };
    }
    // The render function shares the same scope with the constructor
    render() {
        // Use ES6 destructuring to get properties from state and props objects
        const { axles, wheels } = this.state;
        const { editable } = this.props;
        return (<Frame />)
    }
}

Congratulations! You just practiced the creation of Vehicle component, the container encompassing the whole enchilada.

Any component you create can be your primary application scaffold. Usually it's called Application or App.

Here we used Vehicle but it can be anything you want.

We also learned how to "destructure" object properties into individual variable names (axles, wheels, editable) from the upper level components's state and props object. These variables are now readily available for access from within the render method in which they were destructured.

A few words about destructuring { ... } object properties

What is destructuring? It's just a cleaner way of saying:

    let name = this.props.name;
    let value = this.state.value;

It allows us to "destructure" multiple properties into multiple variable names, without having to rewrite heaps of ugly redundant code.

Destructuring allows us to simplify the statements above as:

    let { name, value } = this.state;

Now that looks a lot cleaner! What happened is name and value properties attached to state object are now available for access as variable names in the scope in which they were destructured.

It is recommended to use destructuring in your react components. But, just to give you an idea of the differences, here is exactly the same component with and without destructuring:

Without Destructuring you end up using this.state directly:
With Destructuring you just poll for axles property:
  class Vehicle extends React.Component {
    constructor(props) {
      super(props);
      this.state = { axles: [0, 1, 2] }
    }
    render() {
      return(
        <div>axles = {
          this.state.axles.length }
        </div>
      );} // close render scope
  }// close class scope
  class Vehicle extends React.Component {
    constructor(props) {
      super(props);
      this.state = { axles: [0, 1, 2] }
    }
    render() {
      let { axles } = this.state;
      return(
        <div>axles = {
          axles.length }</div>
      );} // close render scope
  }// close class scope

Be sure to add Babel if you're prototyping directly in the browser (just for testing and practicing the code, never for production build):

    <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>

In real development environments setup for committing to the production server, you will install Babel from the command line instead. But for the demonstrational purpose of this tutorial, you can quickly add Babel, primarily so you can use JSX syntax in your experiments.

How To Properly Handle Nested Return Values From render Method

When I was learning React, I struggled with understanding how to properly return components from the render method. Let's take a look at several examples that gradually build into more complex cases:

  
  // Return an empty container (correct)
  return(<div></div>)

  // Return an empty container, using a self closing tag (correct)
  return(<div />)

  // Return a list of <div> elements using .map method (correct)
  return(<div>
    { this.state.axles.map((object, index) => { return(<div key = {index}>{ index }</div>) } ) }
  </div>)

  // Same as above, except using a self closing <div /> element (correct)
  return(<div>
    { this.state.axles.map((object, index) => { return(<div key = {index} />) } ) }
  </div>)

  // Same as above but cleaner syntax by avoiding second return keyword (correct)
  return(<div>{ this.state.axles.map((object, index) => <div key = {index} />) }</div>)

You can avoid using a second return keyword inside the iterator. This arrow function syntax, where you skip { brackets } automatically assumes that what goes after => will be returned, without having to use the return keyword. This is an ES6 feature.

Iterating Using Array.map Method

As far as mini-architecture of this UI component goes, roughly the following is what we're trying to achieve:

Component scaffold:
After replacing with iterators (pseudo-code):
  <Vehicle>
    <Frame>
      <Axle>
        <Wheel />
        <Wheel />
      </Axle>
      <Axle>
        <Wheel />
        <Wheel />
        <Wheel />
        <Wheel />
      </Axle>
      <Axle>
        <Wheel />
        <Wheel />
        <Wheel />
        <Wheel />
      </Axle>
    </Frame>
  </Vehicle>
  <Vehicle>
    <Frame>
      this.state.axle[0].map((w, i) => {
        return <Axle key = { i } />
      });
      this.state.axle[1].map((w, i) => {
        return <Axle key = { i } />
      });
      this.state.axle[2].map((w, i) => {
        return <Axle key = { i } />
      });
    </Frame>
  </Vehicle>

The ES6 method .map is used here to iterate over all items [0, 1, 2] in the imaginary array this.state.axle;

When we write the actual application, these array objects will be replaced with something more meaningful than just a list of numbers. Perhaps each axle array can contain a list of wheels on that axle.

Every time you use .map iterator inside return you have to provide a  key  pointing to the iterable index (or similar unique ID).

Here is how map method (together with arrow function syntax) works in a nutshell:

  this.state.iterable.map((object, index) => { return <Component idx = {index} obj = {object} /> })

Each one of the JSX-syntax components <Vehicle />, <Frame />, <Axle /> and <Wheel /> must be separately created in the same manner as we created class Vehicle component in the first coding challenge above. You can then store them in separate modules in their respectful files, for example: components/vehicle.js, components/axle.js, components/wheel.js etc.

In this example I hard coded the scaffold to support only 3 axles (we will actually no use this pattern.) I included it only as a mental model for what we're trying to achieve, before going to the next step. Ideally, we want to have a dynamic number of axles. And that's what we will create in the next coding challenge on this page.

Nesting Iterators

We want to iterate through all axles, not just hard code them. Within axle component we will iterate through all wheels attached to that axle. Thankfully, react makes it possible to nest iterators, too. Which makes our React code incredibly compact and highly reusable.

Let's create the Wheels component first. It will contain definition of wheels per axle.

    class Wheels extends React.Component {
        constructor(props) {
            super(props);
            this.state = { wheel: [0, 1]; }  // store some wheels, just the indices for now
        }
        render() {            
            // Destructure wheels property
            let { wheel } = this.state;
            // Iterate through available wheels [0, 1]
            return(<div>{ wheel.map((w, index) => <div key = {index}>{ index }</div> }</div>);     
        }
    }

Now that we have a <Wheels /> component that iterates over the number of wheels stored in it (in this case just the two iterable placeholder values [0, 1]) let's insert it into this.state.axles iterator, which will iterate over Wheels component we just created. All of this is happening within the Frame component we're going to create below:

    class Frame extends React.Component {
        constructor(props) {
            super(props);
            this.state = { axles: [0, 1, 2]; }  // store some axle indices (later can be objects)
        }
        render() {            
            // Destructure axles property
            let { axles } = this.state;
            // Iterate through available axles [0, 1, 2]
            return(<div>{ axles.map((obj, index) =>
                <Wheels key = {index} axle = {obj} /> }</div>);                       
        }
    }

Now we iterate through entire axle array from Frame component's state and within it, we iterate through all the wheels on that axle in <Wheel /> component's render method. We have just successfully nested one iterator within another, effectively giving us the ability to dynamically render axles and wheels associated with them, regardless of their number.

Note that return statement always expects to return some content inside one single wrapper container.

You cannot return a side-by-side pair of elements as in:

 // Generates an error (you cannot return a side-by-side pair of elements):
 return(<div></div><div></div>);

 // Correct (single wrapper container)
 return(<div>Hello there.</div>);

This can be a nuisance in a lot of cases, because it breeds empty container components, where you otherwise may not need one.

You can do the following self-closing syntax with success:

 // This is allowed
 return(<Axles />);

 // You can pass props to self-closing components, as to any other component:
 return(<Axles idx = { index } string = { "text" } />);

Putting It All Together

So far we've explored how to build out the main application scaffold, and created several unique components. Let's put the bits and pieces together. The following example is actually a living breathing React application working directly from this page. It features everything we learned in this tutorial. You can see the source code of this page to see how it works:

  // Add required libraries
  <script crossorigin src = "https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src = "https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>

  Note that we need to specify script as text/babel type in order to use JSX tags
  <script type = "text/babel">

    // Container style
    let container_style = { margin: "auto", width: 130 };

    // Axle container style
    let axle_style = { padding: 4, height: 110 };

    // Truck blocks
    let truck_block = { position: "absolute", top: -25, left: 300 };

    // Wheel container style (a fairly lengthy definition!)
    let wheel_style = { fontFamily: "verdana",
                          fontSize: 12,
                             float: "left",
                            margin: 2,
                           padding: 3,
                             width: 17,
                            height: 50,
                         textAlign: "center",
                        background: "black",
                      borderRadius: 7,
                             color: "white",
                       writingMode: "vertical-rl",
                   textOrientation: "mixed" };

    // Wheel container component
    class Wheels extends React.Component {
      constructor(props) {
        super(props);
      }
      render() {
        return(
          <div>
          { this.props.axle.map((wheel, index) => {
            return(<div key = { index }
            style = { wheel_style }>{ this.props.axle[index] }</div>)
          }) }
          <div style = { truck_block }>
            { /* Find correct image based on the axle index */ }
              <img src = { "truck" + (this.props.index == 0 ? 1 : 2) + ".png" } />
            }
          </div>
      </div>);
      }
    }

  // Axle component
    class Axle extends React.Component {
      constructor(props) {
        super(props);
      }
      render() {
        return(<div style = { axle_style }>
        Axle = { this.props.index }
      <div>{
        <Wheels index = { this.props.index }
                 axle = { this.props.axles[this.props.index] } />
      }</div>
        </div>);
      }
    }

    // Application container
    class Vehicle extends React.Component {
      constructor(props) {
        super(props);
        this.state = { axles: [ ["A","B"], ["C","D","E","F"], ["G","H","I","J"] ] }
      }
      render() {
        let { axles } = this.state;
        return(
          <div style = { container_style }> {
            this.state.axles.map((axle, index) =>
              <Axle key = { index }
                  index = { index }
                  axles = { axles } />)}</div>);
      }
    }

    // Initialize application on the "root" element
    ReactDOM.render(<Vehicle />, document.getElementById("root"));

  </script>

Just copy and paste that into your HTML page, and add the following application container:

  <div id = "root"></div>

Executing the React script will automatically place the results of the render method of the Vehicle component into provided application container <div id = "root"></div> element.

Comments In React

You'll find that standard // comments break your react code. Instead the solution is to encapsulate your comments inside brackets as shown in the following example.

  <div style = { truck_block }>
    { /* Find correct image based on the axle index */ }
    <img src = {"truck" + (this.props.index == 0 ? 1 : 2) + ".png"} />
  </div>

Note that the truck part is dynamically rendered depending on axle index value. Axles under index 0 (there is only one) will render the truck cabin. Axles whose index is greater than 0 will render the trailer box. The ternary JavaScript operator is used to provide an elegant solution for determining the correct truck image per axle.

That's all there is to it! React code is usually clean and performant, considering all the tasks it accomplishes.

Live React Application

Below is a rendering produced by the React application running live on this page (see the source code,) based on the theory discussed in this tutorial. This concludes our nested component tutorial. I think we pretty much beat the subject into extinction.

I hope you enjoyed this nested components tutorial and it helped you learn a thing or two!

Subscribe below to be notified every time there is a new freemium tutorial posted on this site.

© 2017 Copyright React JS Tutorials (reactjstutorial.net)

All content and graphics on this website are the property of reactjstutorial.net - please provide a back link when referencing on other sites.