Edit on GitHub

Lists & Conditional Rendering

Lists #

First, let's review how you transform lists in Javascript.

Given the code below, we use the map() function to take an array of numbers, double their values, and then assigned the new array to the variable doubled.

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2) // result: [2, 4, 6, 8, 10]

In React, transforming arrays into lists of elements is nearly identical.

Rendering Multiple Components #

You can build collections of elements and include them in JSX using curly braces {}, similar to embedding values with Javascript.

Below, we loop through the numbers array using the Javascript map() function. We return an <li> element for each item. Finally, we assign the resulting array of items to listItems. In ReactDOM.render() we render the entire {listItems} array inside a <ul> element.

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((item) =>
  <li>
    {item}
  </li>
);
ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

Try it out on Codepen.

Basic List Component #

We can refactor the previous example into a functional component that accepts an array of numbers and outputs an unordered list of elements.

function NumberList(props) {
  const numbers = props.numbers
  const listItems = numbers.map((item) =>
    <li>
      {item}
    </li>
  );
  return <ul>{listItems}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

When you run this code, you'll be given a warning that a key should be provided for list items. Keys should be included when creating lists of elements.

Let's assign a key to our list items inside numbers.map() and fix the missing key issue.

function NumberList(props) {
  const numbers = props.numbers
  const listItems = numbers.map((item) =>
    <li key={"item-" + item}>
      {item}
    </li>
  );
  return <ul>{listItems}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Try it out on Codepen.

Keys #

Keys help React identify which items have changed, are added, or are removed.

Keys should be given to the elements inside the array to give the elements a stable identity. If you extract a Number component, you should keep the key on the <Number /> elements in the array rather than on the root <li> element in the Number itself.

Keys serve as a hint to React but they don't get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name.

Keys used within groups should be unique to each other.

Example: Incorrect key usage: Should not assign a key in this manner.

function Number(props) {
  return <li key={"item-" + props.value}>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers
  return <ul>{numbers.map((item) => <Number value={item} />}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(<NumberList numbers={numbers} />, document.getElementById('root'));

Example: Correct key usage: Assigns key inside map() function.

function Number(props) {
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers
  return (
    <ul>
    {numbers.map((item) => <Number key={"item-" + item} value={item} />)}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Try it out on Codepen.

Conditional Rendering #

In React, you can create distinct components that encapsulate behavior you need. Then, you can render only the specific component you need, depending on the state of your application.

In this example, we pass the variable loggedIn representing our state, together with the Javascript && operator, and the component we wish to render. Depending on the value of loggedIn the corresponding component will be rendered. React will ignore false and null render output.

function UserGreeting(props) {
  return <div>Welcome back!</div>;
}

function GuestGreeting(props) {
  return <div>Please sign up.</div>;
}

function VisitorMessage(props) {
  let loggedIn = true; // change this to false
  return (
    <div>
      {loggedIn && <UserGreeting />}
      {!loggedIn && <GuestGreeting />}
    </div>
  );
}

ReactDOM.render(<VisitorMessage />, document.getElementById('root'));

Try it out on Codepen

Element Variables #

You can use variables to store elements. This can help you render the specific element you need based on the state of your application.

In the example below, we want to display a login or logout button. In render() we check state.loggedIn and assign to button either <LoginButton /> or <LogoutButton />. We then render the element.

function LogoutButton(props) {
  return <button onClick={props.onClick}>Logout</button>;
}

function LoginButton(props) {
  return <button onClick={props.onClick}>Login</button>;
}

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = {loggedIn: true};
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
  }
  handleLoginClick() {
    this.setState({loggedIn: true});
  }
  handleLogoutClick() {
    this.setState({loggedIn: false});
  }
  render() {
    let button = <LoginButton onClick={this.handleLoginClick} />;
    if (this.state.loggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    }
    return (
      <div>
        {button}
      </div>
    );
  }
}

ReactDOM.render(<LoginControl />, document.getElementById('root'));

Try it out on Codepen.

Inline If-Else With Ternary Operators #

Another method for conditionally rendering elements inline is to use the Javascript ternary operator (condition) ? true : false.

In the example below, we demonstrate how to use the ternary operator to conditionally render a small block of text.

render() {
  let loggedIn = false;
  return (
    <div>
      The user is <strong>{loggedIn?'currently':'not'}</strong> logged in.
    </div>
  );
}

Prevent Component Rendering #

In rare cases you may want to prevent a child component from rendering completely. To do this return null or false from the render() function.

In the example below, the <WarningBanner /> is rendered depending on the value of the prop warn. If the value of the prop is false, then the component does not render.

The highlighted lines below show where the component <WarningBanner /> returns null and the component isn't rendered.

function WarningBanner(props) {
  if(!props.warn) return null;
  return <div className="warning">Warning!</div>;
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true}
    this.toggleWarning = this.toggleWarning.bind(this);
  }
  toggleWarning() {
    this.setState(prevState => ({
      showWarning: !prevState.showWarning
    }));
  }
  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.toggleWarning}>
          {!this.state.showWarning ? "show" : "hide"}
        </button>
      </div>
    );
  }
}

ReactDOM.render(<Page />, document.getElementById('root'));

Try it out on Codepen.