DEV Community

Usama
Usama

Posted on

🧩 Thinking in React: When and Where to Create State (Explained with a Packing List App)

Managing state is one of the most confusing parts for new React developers β€” we often wonder:

β€œShould this be a state, a prop, or a ref?”

In this post, I’ll break down a simple decision-making process to know when to create state and where to put it β€” using my own small project called Listo πŸ›’, a packing list app built with React.


🧠 When to Create State

Ask yourself a few questions before creating new state.


1️⃣ Do I need to store some data?

  • ❌ No: Just use a normal variable.
  const total = price * quantity;
Enter fullscreen mode Exit fullscreen mode
  • βœ… Yes: Go to the next question.

2️⃣ Can this data be computed from existing state or props?

If yes, then don’t store it separately β€” derive it instead.

Example:

const packedCount = items.filter(item => item.packed).length;
Enter fullscreen mode Exit fullscreen mode

No need to store packedCount in useState; it’s derived from items.


3️⃣ Should updating this data re-render the component?

  • ❌ No: Use a ref instead (useRef).
  const inputRef = useRef();
Enter fullscreen mode Exit fullscreen mode

Refs store data without triggering a re-render.

  • βœ… Yes: Go ahead and create local state.
  const [items, setItems] = useState([]);
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Example: My "Listo" App

Here’s how the logic applies to my packing list app.

import { useState } from "react";

function App() {
  const [items, setItems] = useState([]);

  function handleAddItem(item) {
    setItems((items) => [...items, item]);
  }

  return (
    <div className="app">
      <Logo />
      <Form onAddItem={handleAddItem} />
      <PackingList items={items} />
      <Stats />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Where to Place State

Once you decide you need state, the next question is where to keep it.


1️⃣ Is it only used inside one component?

Keep it local.

function Form() {
  const [description, setDescription] = useState("");
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ Is it needed by a child component?

Keep it in the parent and pass it down via props.

<Form onAddItem={handleAddItem} />
Enter fullscreen mode Exit fullscreen mode

3️⃣ Is it needed by multiple siblings?

Then lift the state up to their common parent.

In the Listo app:

  • The Form needs to add new items.
  • The PackingList needs to display those items.

βœ… Solution: Keep items state in the App component and share it via props.


4️⃣ Is it used everywhere in the app?

If many unrelated components need it, you’re dealing with global state.

Use:

  • React Context API
  • or a library like Zustand, Redux, or Jotai

🧩 The Flowchart (Simplified)

Need to store data?
 β”œβ”€β”€ No β†’ Use const
 └── Yes
      β”œβ”€β”€ Can it be derived from props/state?
      β”‚     └── Yes β†’ Derive it
      └── No
           β”œβ”€β”€ Should it re-render component?
           β”‚     └── No β†’ useRef
           └── Yes β†’ useState
Enter fullscreen mode Exit fullscreen mode
Where to place state?
 β”œβ”€β”€ Used only by this component β†’ keep local
 β”œβ”€β”€ Used by a child β†’ move to parent
 β”œβ”€β”€ Used by siblings β†’ lift to common parent
 └── Used globally β†’ global state (context / redux)
Enter fullscreen mode Exit fullscreen mode

✨ Key Takeaways

  1. Don’t overuse state β€” derive values when possible.
  2. Lift state up when multiple components need it.
  3. Refs are great for mutable values that don’t trigger re-renders.
  4. Always ask: β€œWho needs this data?” β€” the answer tells you where the state should live.

πŸ’‘ Bonus: The β€œListo” App in Action

Example list item rendering:

<li>
  <span>
    {item.quantity} {item.unit} β€” {item.description}
  </span>
</li>
Enter fullscreen mode Exit fullscreen mode

Output:

2 kg β€” Apples
Enter fullscreen mode Exit fullscreen mode

πŸš€ Final Thoughts

Thinking in React means thinking about data flow.

When you understand who owns the data and who needs it, managing state becomes simple, predictable, and fun.

β€œIf two components need the same data, lift it up.
If only one needs it, keep it local.
If it doesn’t affect rendering, use a ref.”


✏️ Written by [Usama]
πŸ’» Web Developer sharing my React learning journey
🧺 Built with React: β€œListo” – a simple but powerful packing list app

Top comments (0)