Refactor a Nav Component in React

In this video, we’re going to refactor a Nav component we created in a separate video. We will store the nav menu in the state object in the parent component, and pass it down to the child component to render the data. We’ll use a map() to iterate through the nav data object (JSON-like format) and then use conditional rendering to render the nav to the browser (view).

Here is the video showing how I go over the refactoring process and source code are listed below.

Source code for our NavData (JSON-like format).

const NavData = [
    { "url": "/", "text": "Home", "active": true },
    { "url": "/about", "text": "About", "active": false },
    { "url": "/flights", "text": "Flight List", "active": false },
    { "url": "/add", "text": "Add Flight", "active": false },
]

export default NavData;

The parent component manages the state of these data and passes the data down to the child component to render them.

import React from 'react';
import './App.css';
import Nav from './components/Nav';
import Footer from './components/Footer';
import NavData from './models/NavData';  //JSON data

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { navData : NavData };  //add to the state
  }
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <Nav navData={this.state.navData}/>  {/*pass to child component */}
        </header>
        <Footer />
      </div>
    );
  }
}

export default App;

The child component is refactored and two additional child components are created.

import React from 'react';

//A child component of the Nav component
function NavBarResponsive() {
    return (
        <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
            aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
            <span className="navbar-toggler-icon"></span>
        </button>
    );
}
//A child component of the Nav component
function NavMenu(props) {
    return (
        <div className="collapse navbar-collapse" id="navbarResponsive">
            <ul className="navbar-nav ml-auto">
                {props.navData.map((data, index) => {
                    return (
                        <li key={index} className={data.active ? "nav-item active" : "nav-item"}>
                            <a className="nav-link" href={data.url}>{data.text}
                                {data.active &&
                                    <span className="sr-only">(current)</span>
                                }
                            </a>
                        </li>
                    )
                })
                }
            </ul>
        </div>
    );
}
//A child component of the App component
function Nav(props) {
    return (
        <div>
            {/* --Navigation -- */}
            <nav className="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
                <div className="container">
                    <a className="navbar-brand" href="/">Flight App</a>
                    <NavBarResponsive />
                    <NavMenu navData={props.navData}/>
                </div>
            </nav>
        </div>
    );
}

export default Nav;

On Line 42 of the Nav component, notice how the navData that was passed down from the parent App component is also passed down to the child NavMenu component of the Nav component.

The output of our app.