React.js Fundamentals

Conditional Rendering

15 min Lesson 8 of 40

Understanding Conditional Rendering

Conditional rendering in React allows you to render different UI elements based on certain conditions. Just like JavaScript's conditional statements, you can use if statements, ternary operators, and logical operators to control what gets rendered.

Core Concept: In React, you can create different components or elements and render only the ones you need based on the application state. This makes your UI dynamic and responsive to user interactions and data changes.

Using If/Else Statements

The most straightforward way to conditionally render components is using regular JavaScript if/else statements outside the return statement:

function Greeting({ isLoggedIn }) { if (isLoggedIn) { return <h1>Welcome back!</h1>; } else { return <h1>Please sign in.</h1>; } } // Usage function App() { const [isLoggedIn, setIsLoggedIn] = useState(false); return ( <div> <Greeting isLoggedIn={isLoggedIn} /> <button onClick={() => setIsLoggedIn(!isLoggedIn)}> {isLoggedIn ? 'Logout' : 'Login'} </button> </div> ); }

Ternary Operator

The ternary operator (condition ? true : false) is perfect for inline conditional rendering within JSX:

function UserStatus({ isActive }) { return ( <div> <h2>User Status</h2> <p> You are currently{" "} {isActive ? ( <span style={{ color: 'green' }}>online</span> ) : ( <span style={{ color: 'red' }}>offline</span> )} </p> <div className={isActive ? 'status-active' : 'status-inactive'}> {isActive ? 'Connected' : 'Disconnected'} </div> </div> ); }
Best Practice: Use ternary operators for simple conditions with both true and false cases. For more complex conditions or when you only need to render something in one case, use the logical && operator instead.

Logical AND (&&) Operator

The && operator is ideal when you want to render something only if a condition is true, and render nothing otherwise:

function Notifications({ messages }) { return ( <div> <h2>Inbox</h2> {messages.length > 0 && ( <div className="notification-badge"> You have {messages.length} unread messages </div> )} {messages.length === 0 && ( <p>No new messages</p> )} </div> ); } // Usage function App() { const [messages, setMessages] = useState(['Hello', 'Hi there']); return ( <div> <Notifications messages={messages} /> <button onClick={() => setMessages([])}> Clear Messages </button> </div> ); }
Common Pitfall: Be careful with falsy values on the left side of &&. For example, {count && <div>Count: {count}</div>} will render "0" when count is 0. Instead, use {count > 0 && ...} or {!!count && ...}.

Element Variables

You can store elements in variables and conditionally include them in your render output:

function LoginControl() { const [isLoggedIn, setIsLoggedIn] = useState(false); let button; if (isLoggedIn) { button = <button onClick={() => setIsLoggedIn(false)}>Logout</button>; } else { button = <button onClick={() => setIsLoggedIn(true)}>Login</button>; } let message; if (isLoggedIn) { message = <p>You have access to premium features.</p>; } else { message = <p>Please log in to access premium features.</p>; } return ( <div> <h1>Account Status</h1> {message} {button} </div> ); }

Multiple Conditions with Switch

For multiple conditions, you can use switch statements or create a mapping object:

function StatusMessage({ status }) { // Method 1: Switch statement const getMessageWithSwitch = () => { switch(status) { case 'loading': return <div className="spinner">Loading...</div>; case 'success': return <div className="success">Data loaded successfully!</div>; case 'error': return <div className="error">Failed to load data.</div>; default: return <div>No status</div>; } }; // Method 2: Object mapping (cleaner) const statusComponents = { loading: <div className="spinner">Loading...</div>, success: <div className="success">Data loaded successfully!</div>, error: <div className="error">Failed to load data.</div>, idle: <div>No status</div> }; return ( <div> {/* Using switch */} {getMessageWithSwitch()} {/* Or using object mapping */} {statusComponents[status] || statusComponents.idle} </div> ); }

Rendering Nothing (Null)

Sometimes you want a component to hide itself. Return null to render nothing:

function WarningBanner({ warning, onClose }) { if (!warning) { return null; // Don't render anything } return ( <div className="warning-banner"> <span>{warning}</span> <button onClick={onClose}>×</button> </div> ); } // Usage function App() { const [warning, setWarning] = useState('Your session will expire in 5 minutes'); return ( <div> <WarningBanner warning={warning} onClose={() => setWarning(null)} /> <h1>Dashboard</h1> </div> ); }
Important: Returning null from a component does not affect the lifecycle methods. The component still mounts and updates normally, it just doesn't render anything visible.

Conditional CSS Classes

You can conditionally apply CSS classes to change the appearance of elements:

function Button({ isPrimary, isDisabled, children }) { // Method 1: Template literals const className1 = `btn ${isPrimary ? 'btn-primary' : 'btn-secondary'} ${isDisabled ? 'btn-disabled' : ''}`; // Method 2: Array join const className2 = [ 'btn', isPrimary ? 'btn-primary' : 'btn-secondary', isDisabled && 'btn-disabled' ].filter(Boolean).join(' '); // Method 3: Object-based (requires classnames library) // const className3 = classnames({ // 'btn': true, // 'btn-primary': isPrimary, // 'btn-secondary': !isPrimary, // 'btn-disabled': isDisabled // }); return ( <button className={className1} disabled={isDisabled}> {children} </button> ); } // Usage function App() { return ( <div> <Button isPrimary={true} isDisabled={false}> Save </Button> <Button isPrimary={false} isDisabled={false}> Cancel </Button> <Button isPrimary={true} isDisabled={true}> Loading... </Button> </div> ); }

Complex Conditional Rendering Example

Here's a real-world example combining multiple conditional rendering techniques:

function UserDashboard({ user, isLoading, error }) { // Early returns for special cases if (isLoading) { return <div className="loading">Loading user data...</div>; } if (error) { return ( <div className="error-container"> <h2>Error</h2> <p>{error.message}</p> <button onClick={() => window.location.reload()}> Retry </button> </div> ); } if (!user) { return <div>No user found</div>; } // Main render with nested conditions return ( <div className="dashboard"> <h1>Welcome, {user.name}!</h1> {/* Conditional badge */} {user.isPremium && ( <span className="premium-badge">Premium Member</span> )} {/* Conditional content based on account type */} {user.accountType === 'admin' ? ( <AdminPanel /> ) : user.accountType === 'moderator' ? ( <ModeratorPanel /> ) : ( <UserPanel /> )} {/* Conditional notification */} {user.notifications.length > 0 && ( <div className="notifications"> <h3>You have {user.notifications.length} notifications</h3> {user.notifications.map(notif => ( <div key={notif.id}>{notif.message}</div> ))} </div> )} {/* Conditional warning */} {!user.emailVerified && ( <div className="warning"> Please verify your email address </div> )} </div> ); }
Performance Tip: Use early returns for special cases (loading, error, no data) at the top of your component. This keeps your main render logic clean and easier to understand.

Exercise 1: Todo List with Filters

Create a todo list with conditional rendering for different views:

  • Display "All", "Active", and "Completed" filter buttons
  • Show different lists based on the selected filter
  • If no todos match the filter, show "No todos found" message
  • Show a counter: "X active todos" (only if there are active todos)
  • Show a "Clear completed" button (only if there are completed todos)
  • Show different styles for completed vs active todos

Hint: Use state to track the current filter and use conditional rendering to show the appropriate todos.

Exercise 2: Authentication Flow

Build a component that renders different screens based on authentication state:

  • Show a loading spinner while checking authentication
  • Show login form if not authenticated
  • Show user dashboard if authenticated
  • Show error message if authentication failed
  • In the dashboard, show admin tools only if user is an admin
  • Show a welcome banner only on first login (track with state)

Bonus: Add a "remember me" checkbox that conditionally displays in the login form.

Exercise 3: Product Card with Conditional Features

Create a product card component with various conditional elements:

  • Show "Sale" badge if product has a discount
  • Show original price (crossed out) and sale price if on sale
  • Show "Out of Stock" message if quantity is 0
  • Disable "Add to Cart" button if out of stock
  • Show star rating only if product has reviews
  • Show "New" badge if product was added within last 7 days
  • Apply different CSS classes based on product category

Hint: Pass a product object with properties like price, salePrice, quantity, rating, createdAt, and category.