Try   HackMD

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

React | Conditional Rendering

Learning Goals

After this lesson you will be able to:

  • Render component according to conditions
  • Understand how to implement conditional rendering in React
  • Implement ternary operator for conditional render

Introduction

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

Conditional rendering in React works the same way conditions work in JavaScript. Use JavaScript operators like if or the conditional operator to create elements representing the current state, and let React update the UI to match them.

Example:

if (true) {
    return <SomeComponentGoesHere/>
} else {
    return <OtherComponentGoesHere/>
}

While using an if statement is a fine way to conditionally render a component, sometimes you might want to use a shorter syntax. There are a few ways to inline conditions in JSX. One way to go about this is using ternary operator: condition ? true : false.

Simple conditional rendering an object

Let's keep working within our small project and our next step is to slightly update our movies array in the state of <DynamicMoviesList /> component:

Reprise du projet my-new-app et modification des datas pour ajouter les champs hasOscars et IMDbRating aux objects movies :

// components/dynamicListsDemo/DynamicMoviesList.js

...
class DynamicMoviesList extends Component {
    constructor(props) {
        super(props);
        
        this.state = {
            movies: [
                { id: "fUbJPciPq", title: "The Godfather", director: "Francis Coppola", hasOscars: true, IMDbRating: 9.2 },
                { id: "EXN9npPlo",  title: "Star Wars", director: "Rian Johnson" , hasOscars: true, IMDbRating: 8.7 },
                { id: "lecqGHnAb",  title: "The Shawshank Redemption", director: "Frank Darabont", hasOscars: false, IMDbRating: 9.3 }
            ]
        }
    }
    ...
}

Nothing's still changed in our app, we still can see the same result. So let's make some changes in our <ImprovedCard /> component. We can implement inline ternary operator for more straightforward logic:

Nous allons maintenant, grâce à l'opérateur ternaire, afficher si oui ou non un film a reçu un oscar grâce à la nouvelle donnée hasOscars

// components/dynamicListsDemo/ImprovedCard.js
import React from 'react';

const ImprovedCard = (props) => {
    return (
        <div className="movies-list-item">
            <h2>{props.title}</h2>
            <p>Director: {props.director}</p>
            {
                props.hasOscars ? 
                <p>Got the Oscar Award! 😉 </p>
                :
                <p>Great movie but no Oscars! 😔 </p>
            }
            <button onClick={props.clickToDelete}>Delete</button>
        </div>
    )
};

export default ImprovedCard;

Plus simple que de définir une fonction utilitaire :

function displayOscars(hasOscars) {
  if (hasOscars) {
    return <p>Got the Oscar Award! 😉 </p>;
  } else {
    return <p>Great movie but no Oscars! 😔 </p>;
  }
}

appelée par:

...
{displayOscars(props.hasOscars)}

On remarque aussi la présence des {} autour :

{
  props.hasOscars ?
    // OUI
    :
    // NON
}

On oublie pas non plus que la valeur retournée doit être dans une balise englobante :

  return (
    ...
    
    {
      props.hasOscars ?
        <div>
          <p>Got the Oscar Award!</p>
          <p>🎉 Samba!</p>
        </div>
        :
        <p>Pas d'oscar 😭</p>
    }
    ...
  );

Even simpler logic

Let's use a more outstanding approach that has better use of JS grammar. You may embed any expressions in JSX by wrapping them in curly braces. This includes the JavaScript logical && operator. Let's update code in our ImprovedCard.js:

Opérateurs booléens: &&, ||

// components/dynamicListsDemo/ImprovedCard.js
import React from 'react';

const ImprovedCard = (props) => {
    return (
        <div className="movies-list-item">
            <h2>{props.title}</h2>
            <p>Director: {props.director}</p>

            { props.hasOscars && <p>Got the Oscar Award! 😉 </p> }
            { !props.hasOscars && <p>Great movie but no Oscars! 😔 </p> }

            <button onClick={props.clickToDelete}>Delete</button>
        </div>
    )
};

export default ImprovedCard;

It works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to false.
Therefore, if the condition is true, the element right after && will appear in the output. If it is false, React will ignore and skip it.

Si plus complexe qu'un simple if/else => recours aux variables avant le return

If the conditional rendering logic is a more complex, which is not in our case but we will use this example to demonstrate the approach, it is better to extract condition outside JSX:

// components/dynamicListsDemo/ImprovedCard.js
import React from 'react';

const ImprovedCard = (props) => {
    let awardText;
    if(props.hasOscars){
        if(props.IMDbRating >= 9){
            awardText = <p> WOW! Oscar Award and IMDb rating {props.IMDbRating}! </p>
        } else if(props.IMDbRating >= 7){
            awardText = <p> Got the Oscar Award and has IMDb rating {props.IMDbRating}, not bad at all! </p>
        }
    } else {
        awardText = <p> Great movie but no Oscars! Has IMDb rating {props.IMDbRating}. </p>
    }
    
    return (
        <div className="movies-list-item">
            <h2>{props.title}</h2>
            <p>Director: {props.director}</p>
            {awardText}
            <button onClick={props.clickToDelete}>Delete</button>
        </div>
    )
};

export default ImprovedCard;

State conditional rendering

The other way of displaying the movies in the <DynamicMoviesList /> component could be something like this:

Nous allons maintenant filtrer la liste des films, en fonction de s'ils ont ou non remportés un oscar :

// components/dynamicListsDemo/DynamicMoviesList.js ... class DynamicMoviesList extends Component { constructor(props) { super(props); this.state = { movies: [ { id: "fUbJPciPq", title: "The Godfather", director: "Francis Coppola", hasOscars: true, IMDbRating: 9.2 }, { id: "EXN9npPlo", title: "Star Wars", director: "Rian Johnson" , hasOscars: true, IMDbRating: 8.7 }, { id: "lecqGHnAb", title: "The Shawshank Redemption", director: "Frank Darabont", hasOscars: false, IMDbRating: 9.3 } ], showOscarAwarded: false // 👈 } } // 👇 toggleMovies = () => { this.setState({ showOscarAwarded: !this.state.showOscarAwarded }) } ... render() { console.log(this.state.movies); // 👇 Filter movies based on `this.props.showOscarAwarded` value const {showOscarAwarded} = this.state; const filteredMovies = this.state.movies.filter(theMovie => theMovie.hasOscars === showOscarAwarded); return ( <div> {/* 👇 Display filtered movies */} {filteredMovies.map(=item => { return <ImprovedCard key={item.id} {...item} clickToDelete={() => this.deleteMovieHandler(item.id)} /> })} {/* 👇 Toggle */} <button onClick={() => this.toggleMovies() }> {showOscarAwarded ? 'Hide Oscar Awarded' : 'Show Oscar Awarded'} </button> </div> ); } }

Nous affichons maintenant une liste de films, filtrés avec la valeur de l'état this.props.showOscarAwarded. La liste filtrée est "calculée" à chaque render()

Nous ré-initialisons la liste de films à chaque appel à this.toggleMovies

Notons aussi l'utilisation de l'opérateur ternaire ligne 41.

Practice

Take a look of the following example and play around with it:

Summary

Conditional rendering is one of the most common ways to show/hide components in React apps. When developing your applications you will find situations where you want to display specific components depending on some variables, so be sure to understand how to implement the conditional rendering.

Extra Resources