--- tags: ironhack, lecture, --- <style> .markdown-body img[src$=".png"] {background-color:transparent;} .alert-info.lecture, .alert-success.lecture, .alert-warning.lecture, .alert-danger.lecture { box-shadow:0 0 0 .5em rgba(64, 96, 85, 0.4); margin-top:20px;margin-bottom:20px; position:relative; ddisplay:none; } .alert-info.lecture:before, .alert-success.lecture:before, .alert-warning.lecture:before, .alert-danger.lecture:before { content:"👨‍🏫\A"; white-space:pre-line; display:block;margin-bottom:.5em; /*position:absolute; right:0; top:0; margin:3px;margin-right:7px;*/ } b { --color:yellow; font-weight:500; background:var(--color); box-shadow:0 0 0 .35em var(--color),0 0 0 .35em; } .skip { opacity:.4; } </style> ![logo_ironhack_blue 7](https://user-images.githubusercontent.com/23629340/40541063-a07a0a8a-601a-11e8-91b5-2f13e4e6b441.png) # 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: ```jsx 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: :::info lecture Reprise du projet `my-new-app` et modification des datas pour **ajouter les champs `hasOscars` et `IMDbRating`** aux objects movies : ::: ```jsx // 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: :::info lecture 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` ::: ```jsx // 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; ``` :::info lecture Plus simple que de définir une fonction utilitaire : ```jsx function displayOscars(hasOscars) { if (hasOscars) { return <p>Got the Oscar Award! 😉 </p>; } else { return <p>Great movie but no Oscars! 😔 </p>; } } ``` appelée par: ```jsx ... {displayOscars(props.hasOscars)} ``` ::: :::info lecture On remarque aussi la présence des `{}` autour : ```jsx { props.hasOscars ? // OUI : // NON } ``` ::: :::info lecture On oublie pas non plus que la valeur retournée doit être dans une balise englobante : ```jsx 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*: :::info lecture Opérateurs booléens: `&&`, `||` ::: ```jsx // 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. :::info lecture 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: ```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: :::info lecture Nous allons maintenant filtrer la liste des films, en fonction de s'ils ont ou non remportés un oscar : ::: ```jsx= // 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> ); } } ``` :::info lecture 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()` ::: :::info lecture Nous ré-initialisons la liste de films à chaque appel à `this.toggleMovies` ::: :::info lecture Notons aussi l'utilisation de l'opérateur ternaire ligne 41. ::: ### Practice Take a look of the following example and play around with it: <iframe height='265' scrolling='no' title='Preventing Component Rendering' src='//codepen.io/ironhack/embed/GBwKdo/?height=265&theme-id=0&default-tab=js,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='https://codepen.io/ironhack/pen/GBwKdo/'>Preventing Component Rendering</a> by Ironhack (<a href='https://codepen.io/ironhack'>@ironhack</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> :::info lecture Ma version : https://codepen.io/abernier/pen/EMaYob?editors=1010 ::: ## 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 - [React Conditional Rendering](https://reactjs.org/docs/conditional-rendering.html)