Conditional rendering is showing content dynamically based on values that can change over time. This can be done inline in the template using interpolation with conditionals, or by returning a component or JSX from a function. Using these methods dynamic content can be controlled at the template level.
Inline Conditionals
Inline content can be managed using any Javascript comparison operators. These operations will be done inside the JSX returned or rendered by a component in React. Logic can be executed inside of interpolation, which is represented by the curly braces inside of the html {}. While the html is static, whatever is interpolated is dynamic.
interface HelloHeaderProps { name: string; isLoggedIn: boolean; } export const HelloComponent = ({ name, isLoggedIn }: HelloHeaderProps): JSX.Element => <h1>Hello {isLoggedIn && name}</h1>;
It is important to note, when using interpolation you can either return the raw value or you can return wrapped JSX. It must be wrapped in at least one element or html tag if you are returning JSX.
export const HelloComponent = ({ name, isLoggedIn }: HelloHeaderProps): JSX.Element => <h1>Hello {isLoggedIn && <u>name</u>}</h1>;
Ternaries and equalities can also be used inline.
<div> { favoriteAnimal === AnimalsEnum.cow ? <span>my favorite animal is a cow too!</span> : <span>there are cooler animals</span> } </div>
Rendering from Functions
Rendering can be dynamic by invoking a function as well, one that either returns JSX or a component
class VendingMachine extends Component<VendingMachineProps, VendingMachineState> { constructor(props) { super(props); this.state = { selectionMade: false, selection: SnackEnum } } getSnack(): JSX.element { switch(this.state.selection) { case SnackEnum.chips: return <span>it's chips!</span> case SnackEnum.cookies: return <span>it's cookies!</span> case snackEnum.redbull: return <span>it's a half a can of redbull!</span> default: return <span>ya got robbed :(</span> } } setSelection(snack: SnackEnum) { this.setState((state) => ({ ...state, selectionMade: true, selection: snackEnum.redbull })) } render() { return ( <div> <VendingName /> <VendingGrid /> <Keypad onSelectionMade={this.setSelection.bind(this)}/> <VendingPort /> <div> <span>You got a snack!</span> { this.state.selectionMade && getSnack() } </div> </div> ) } }
This would render out the appropriate snack message for whichever snack the user got from the vending machine. But rendering JSX should be reserved for very simple template changes. As more snacks get added, this method gets more complex. To keep this function from getting too large, each snack should be its own component.
... getSnack(): JSX.element { switch(this.state.selection) { case SnackEnum.chips: return <Chips /> case SnackEnum.cookies: return <Cookies /> case snackEnum.redbull: return <HalfACanOfRedbull /> default: return <Robbed /> } } ... render() { return ( <div> <VendingName /> <VendingGrid /> <Keypad onSelectionMade={this.setSelection}/> <VendingPort /> <div> <span>You got a snack!</span> { this.state.selectionMade && getSnack() } </div> </div> ) }
Conditional Styling
Styling can be handled in a very similar way, using any sort of Javascript comparison operators or ternaries. In React, this can be done by using the style attribute.
export const TextValidatorMessage = ({ isError, text }: textValidatorProps): JSX.Element => <span style={ isError ? {color: 'red' } : { color: 'green' }}>{ text }</span>;
This could also be done using an imported style sheet, for more complex styles.
import styles from './TextValidatorStyles.js'; ... export const TextValidatorMessage = ({ isError, text }: textValidatorProps): JSX.Element => <span style={ isError ? styles.ErrorMessage : styles.InfoMessage }>{ text }</span>;
That’s a wrap
Conditional rendering is a great tool. As complexity grows, make sure to separate code into smaller pieces, and separate files. No one wants to refactor a legacy behemoth component, and it will make debugging much easier. Thanks for reading and make sure to check out our other articles on React.