The Pragmatic Developer

The Pragmatic Developer

Share this post

The Pragmatic Developer
The Pragmatic Developer
Solution to Design Challenge 009: Two Ways to Refactor a Status-Driven UI in React

Solution to Design Challenge 009: Two Ways to Refactor a Status-Driven UI in React

Component extraction vs. helper refactor — which scales better?

Juntao Qiu's avatar
Juntao Qiu
Jun 17, 2025
∙ Paid
1

Share this post

The Pragmatic Developer
The Pragmatic Developer
Solution to Design Challenge 009: Two Ways to Refactor a Status-Driven UI in React
Share

If you're new to this series, here's a quick recap: in each Design Challenge, I present a real-world frontend problem (usually React-related), and a week later I follow up with the refactoring or solution I applied.

In last week's challenge, we looked at a component called DirectToBoot that changes its UI based on different order statuses — from loading, to ready for pickup, to error handling. This week, I'll walk you through two practical approaches to refactor that logic.

This example is part of the newly updated edition of my book, Maintainable React — if you haven’t checked it out yet, you can use that link for a 50% discount.

The original implementation worked — but it was cluttered, with conditional checks scattered across the component. In this issue, I’ll walk you through two practical ways to refactor that code to make it more maintainable and scalable.


🧱 Option 1: Extract Helper Structures

This approach is the simplest: keep the main structure but extract the pieces of logic that are repeated or too verbose inline.

✅ Step 1: Extract a statusMessages map

const statusMessages: Record<Status, string> = {
  initialised: "We're preparing your order...",
  ready: "Please click the button when you have arrived...",
  notified: "Thanks for letting us know...",
  error: "Something went wrong. Please call the number below.",
};

✅ Step 2: Extract an ActionButton component

function ActionButton({ status, onNotify }) {
  switch (status) {
    case "initialised":
      return <button className="primaryButton" disabled>I'm here</button>;
    case "ready":
      return <button className="primaryButton" onClick={onNotify}>I'm here</button>;
    case "error":
      return <a href="tel:042333" className="primaryButton">Call us</a>;
    default:
      return null;
  }
}

🧼 Cleaner JSX

export function DirectToBoot({ orderId }: { orderId: string }) {
  const [status, setStatus] = useState<Status>("initialised");

  const handleNotify = () => {
    mutation.mutate(orderId);
  };

  return (
    <div className="container">
      <h3>Direct To Boot</h3>
      <p>{statusMessages[status]}</p>
      <ActionButton status={status} onNotify={handleNotify} />
    </div>
  );
}

This keeps the logic inline but improves readability. You still work in one file, but without burying the core UI in conditionals.

black and red stick vacuum cleaner
Photo by eMotion Tech on Unsplash

🧩 Option 2: One Component Per Status

This second approach fully separates the logic for each status into its own component.

Keep reading with a 7-day free trial

Subscribe to The Pragmatic Developer to keep reading this post and get 7 days of free access to the full post archives.

Already a paid subscriber? Sign in
© 2025 Juntao Qiu
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share