DEV Community

Happy
Happy

Posted on

A Simple React + TypeScript Pattern to Replace Nested if/else

A Simple React + TypeScript Pattern to Replace Nested if/else

When I started building React apps, I wrote many nested if/else blocks in components.
It worked, but after a few weeks, the code became hard to read.

Today I want to share a small pattern that helps a lot:
use a status map object instead of long condition chains.

This is beginner-friendly, and you can use it right away.

The problem

Imagine you load user data from an API.
Your UI has 4 states:

  • loading
  • error
  • empty
  • success

Many people write something like this:

if (isLoading) {
  return <p>Loading...</p>
} else if (isError) {
  return <p>Something went wrong</p>
} else if (users.length === 0) {
  return <p>No users yet</p>
} else {
  return <UserList users={users} />
}
Enter fullscreen mode Exit fullscreen mode

This is okay at first. But it gets messy when states grow.

A cleaner pattern: status map

Create one status value, then map it to UI.

type Status = 'loading' | 'error' | 'empty' | 'success'

function UsersPanel({
  status,
  users,
}: {
  status: Status
  users: { id: number; name: string }[]
}) {
  const viewByStatus: Record<Status, React.ReactNode> = {
    loading: <p>Loading...</p>,
    error: <p>Something went wrong</p>,
    empty: <p>No users yet</p>,
    success: <UserList users={users} />,
  }

  return <section>{viewByStatus[status]}</section>
}
Enter fullscreen mode Exit fullscreen mode

Why this is nice:

  1. You can see all states in one place.
  2. It is easier to scan and update.
  3. TypeScript checks that you did not forget a state.

Tiny vitest example

You can test this logic quickly.

import { describe, expect, it } from 'vitest'

type Status = 'loading' | 'error' | 'empty' | 'success'

function getMessage(status: Status) {
  const messageByStatus: Record<Status, string> = {
    loading: 'Loading...',
    error: 'Something went wrong',
    empty: 'No users yet',
    success: 'Data ready',
  }

  return messageByStatus[status]
}

describe('getMessage', () => {
  it('returns the loading text', () => {
    expect(getMessage('loading')).toBe('Loading...')
  })
})
Enter fullscreen mode Exit fullscreen mode

When to use this

Use this pattern when:

  • you have clear finite states
  • UI changes by state
  • condition chains are becoming long

If the logic becomes very complex, a state machine can be the next step.
But for many apps, this simple map pattern is enough.


If you use React + TypeScript + Vite, try this in your next component.
Small patterns like this make code easier to maintain over time.

Top comments (0)