javascript-today

Conditional Rendering

What is Conditional Rendering?

Conditional rendering is showing different UI based on certain conditions. Just like if/else in JavaScript, you can control what gets displayed in your React components.

function Greeting({ isLoggedIn }) {
  if (isLoggedIn) {
    return <h1>Welcome back!</h1>;
  }
  return <h1>Please sign in.</h1>;
}

if/else Statements

Basic if/else

function LoginStatus({ isLoggedIn }) {
  if (isLoggedIn) {
    return <p>You are logged in</p>;
  } else {
    return <p>Please log in</p>;
  }
}

With Variables

function Dashboard({ user }) {
  let content;
  
  if (user.isAdmin) {
    content = <AdminPanel />;
  } else {
    content = <UserPanel />;
  }
  
  return (
    <div>
      <h1>Dashboard</h1>
      {content}
    </div>
  );
}

Multiple Conditions

function StatusMessage({ status }) {
  if (status === 'loading') {
    return <p>Loading...</p>;
  }
  
  if (status === 'error') {
    return <p style={{ color: 'red' }}>Error occurred!</p>;
  }
  
  if (status === 'success') {
    return <p style={{ color: 'green' }}>Success!</p>;
  }
  
  return <p>Ready</p>;
}

Early Return Pattern

Return early to avoid nesting:

Loading State

function UserProfile({ user, isLoading }) {
  if (isLoading) {
    return <p>Loading user profile...</p>;
  }
  
  if (!user) {
    return <p>User not found</p>;
  }
  
  // Main content
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

Error Handling

function DataDisplay({ data, error }) {
  if (error) {
    return <div className="error">{error.message}</div>;
  }
  
  if (!data) {
    return <div>No data available</div>;
  }
  
  return (
    <div>
      <h2>Data:</h2>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

Ternary Operator (? :)

For simple if/else, use ternary operator inline:

Basic Ternary

function Message({ isOnline }) {
  return (
    <div>
      <p>User is {isOnline ? 'online' : 'offline'}</p>
    </div>
  );
}

Rendering Components

function AuthButton({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? (
        <button>Log Out</button>
      ) : (
        <button>Log In</button>
      )}
    </div>
  );
}

With Different Components

function Content({ hasPermission }) {
  return (
    <div>
      {hasPermission ? (
        <SecretContent />
      ) : (
        <AccessDenied />
      )}
    </div>
  );
}

Nested Ternaries (Be Careful!)

function StatusBadge({ status }) {
  return (
    <span className={
      status === 'active' ? 'badge-green' :
      status === 'pending' ? 'badge-yellow' :
      'badge-gray'
    }>
      {status}
    </span>
  );
}

// Better: use if/else or switch for multiple conditions

Logical && Operator

Show something only when condition is true:

Basic &&

function Notifications({ count }) {
  return (
    <div>
      <h2>Notifications</h2>
      {count > 0 && <p>You have {count} new notifications</p>}
    </div>
  );
}

Showing Components

function AdminPanel({ isAdmin }) {
  return (
    <div>
      <h1>Dashboard</h1>
      {isAdmin && <AdminControls />}
      {isAdmin && <UserManagement />}
    </div>
  );
}

Multiple Conditions

function ProfileBadge({ user, isPremium, isVerified }) {
  return (
    <div>
      <h2>{user.name}</h2>
      {isPremium && <span className="badge">Premium</span>}
      {isVerified && <span className="badge">Verified </span>}
    </div>
  );
}

Watch Out for Falsy Values

// ❌ Bad - shows "0" when count is 0
function Items({ count }) {
  return (
    <div>
      {count && <p>You have {count} items</p>}
    </div>
  );
}
// When count is 0, React renders "0"!

// ✅ Good - explicitly check
function Items({ count }) {
  return (
    <div>
      {count > 0 && <p>You have {count} items</p>}
    </div>
  );
}

Logical || Operator

Show fallback when value is falsy:

function Welcome({ username }) {
  return <h1>Hello, {username || 'Guest'}!</h1>;
}

function Avatar({ imageUrl }) {
  return (
    <img 
      src={imageUrl || '/default-avatar.png'} 
      alt="Profile" 
    />
  );
}

Note: Use nullish coalescing ?? to only fallback on null/undefined:

function Counter({ count }) {
  // || would show fallback for 0
  return <p>Count: {count ?? 'Not set'}</p>;
}

Switch Statements

For multiple mutually exclusive conditions:

function StatusIcon({ status }) {
  let icon;
  
  switch (status) {
    case 'success':
      icon = '✓';
      break;
    case 'error':
      icon = '✗';
      break;
    case 'warning':
      icon = '⚠';
      break;
    case 'info':
      icon = 'ℹ';
      break;
    default:
      icon = '○';
  }
  
  return <span className={`icon-${status}`}>{icon}</span>;
}

With Components

function PageContent({ page }) {
  switch (page) {
    case 'home':
      return <HomePage />;
    case 'about':
      return <AboutPage />;
    case 'contact':
      return <ContactPage />;
    case 'profile':
      return <ProfilePage />;
    default:
      return <NotFoundPage />;
  }
}

Object Mapping Pattern

Cleaner alternative to switch for component selection:

function PageContent({ page }) {
  const pages = {
    home: <HomePage />,
    about: <AboutPage />,
    contact: <ContactPage />,
    profile: <ProfilePage />
  };
  
  return pages[page] || <NotFoundPage />;
}

With Functions

function Icon({ type }) {
  const icons = {
    success: () => <span></span>,
    error: () => <span></span>,
    warning: () => <span></span>,
    info: () => <span></span>
  };
  
  const IconComponent = icons[type] || icons.info;
  return <IconComponent />;
}

Common Patterns

1. Loading State

function DataFetcher({ isLoading, data, error }) {
  if (isLoading) {
    return <div className="spinner">Loading...</div>;
  }
  
  if (error) {
    return <div className="error">Error: {error.message}</div>;
  }
  
  return (
    <div className="data">
      {data.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
}

2. Empty State

function TodoList({ todos }) {
  if (todos.length === 0) {
    return (
      <div className="empty-state">
        <p>No todos yet!</p>
        <button>Add your first todo</button>
      </div>
    );
  }
  
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
}

3. Permission-Based Rendering

function ActionButtons({ canEdit, canDelete }) {
  return (
    <div className="actions">
      <button>View</button>
      {canEdit && <button>Edit</button>}
      {canDelete && <button>Delete</button>}
    </div>
  );
}

4. Feature Flags

function App({ features }) {
  return (
    <div>
      <Header />
      {features.showBanner && <PromoBanner />}
      <MainContent />
      {features.showChat && <ChatWidget />}
      {features.newDesign ? <NewFooter /> : <OldFooter />}
    </div>
  );
}

5. Authentication

function App({ user }) {
  if (!user) {
    return <LoginPage />;
  }
  
  return (
    <div>
      <Header user={user} />
      <Dashboard />
      {user.isAdmin && <AdminPanel />}
    </div>
  );
}

6. Conditional CSS Classes

function Button({ isPrimary, isDisabled, children }) {
  const className = [
    'btn',
    isPrimary && 'btn-primary',
    isDisabled && 'btn-disabled'
  ].filter(Boolean).join(' ');
  
  return <button className={className}>{children}</button>;
}

// Or with template literals
function Button({ isPrimary, isDisabled, children }) {
  return (
    <button className={`
      btn
      ${isPrimary ? 'btn-primary' : ''}
      ${isDisabled ? 'btn-disabled' : ''}
    `.trim()}>
      {children}
    </button>
  );
}

Conditional Rendering with Arrays

Filter and Map

function ProductList({ products, showOnSale }) {
  return (
    <div>
      {products
        .filter(product => !showOnSale || product.onSale)
        .map(product => (
          <ProductCard key={product.id} product={product} />
        ))}
    </div>
  );
}

Multiple Conditions

function UserList({ users, showActive, showPremium }) {
  return (
    <div>
      {users
        .filter(user => {
          if (showActive && !user.isActive) return false;
          if (showPremium && !user.isPremium) return false;
          return true;
        })
        .map(user => (
          <UserCard key={user.id} user={user} />
        ))}
    </div>
  );
}

Best Practices

DO:

// Use early returns for error/loading states
function Component({ data, isLoading, error }) {
  if (isLoading) return <Spinner />;
  if (error) return <Error />;
  return <Content data={data} />;
}

// Use ternary for simple if/else
<div>{isLoggedIn ? <LogoutButton /> : <LoginButton />}</div>

// Use && for showing content when true
{hasNotifications && <NotificationBadge />}

// Explicitly check numbers
{count > 0 && <p>Count: {count}</p>}

// Use switch/object mapping for multiple cases
const views = {
  home: <Home />,
  profile: <Profile />
};

DON’T:

// Don't use && with numbers that could be 0
{count && <p>{count} items</p>}  // Shows "0" when count is 0!

// Don't nest ternaries too deeply
{a ? (b ? c : d) : (e ? f : g)}  // Hard to read!

// Don't forget null can be rendered
{user.name && <p>{user.name}</p>}  // What if name is null?

// Don't use if/else for simple inline cases
let button;
if (isLoggedIn) {
  button = <LogoutButton />;
} else {
  button = <LoginButton />;
}
return <div>{button}</div>;
// Better: {isLoggedIn ? <LogoutButton /> : <LoginButton />}

Choosing the Right Method

Method Use Case Example
if/else Multiple statements, complex logic Loading/error handling
Early return Guard clauses, error handling Validation, permissions
Ternary ? : Simple if/else inline {isOn ? 'On' : 'Off'}
Logical && Show when true {isAdmin && <Panel />}
Switch Multiple exclusive options Page routing, status icons
Object map Dynamic component selection Feature flags, themes

Quick Guide:

  • 2 options → Ternary or if/else
  • Show/hide one thing → &&
  • 3+ options → Switch or object map
  • Complex logic → if/else with early returns

Summary

Basic Syntax:

// if/else
if (condition) {
  return <ComponentA />;
} else {
  return <ComponentB />;
}

// Ternary
{condition ? <ComponentA /> : <ComponentB />}

// Logical &&
{condition && <Component />}

// Early return
if (!data) return <Loading />;
return <Content />;

Common Patterns:

  • Loading states: Early return with if
  • Show/hide: Logical &&
  • A or B: Ternary operator
  • Multiple cases: Switch or object map

Remember:

  • 0 and "" render in React (avoid {count && ...})
  • null, undefined, true, false don’t render
  • Use >= 0, !== '' for explicit checks