Skip to content

React Tutorial State and Events

Multiple State Variables vs One State Object

Lesson 53 of 156 2 min read By Deepak Paswan Updated Oct 10, 2026

Runnable lesson · press Try it on the examples to edit and run them here.

A component often has several pieces of state. Do you create one useState for each, or a single object? Both work. This lesson gives you a way to decide.

Several separate states

You can call useState as many times as you need:

App.jsx
JSX
function App() {
  const [name, setName] = React.useState("Ada");
  const [age, setAge] = React.useState(36);
  const [city, setCity] = React.useState("London");

  return (
    <div>
      <p>{name}, {age}, {city}</p>
      <button onClick={() => setAge(age + 1)}>Birthday</button>
    </div>
  );
}

Each useState is independent. Changing age does not touch name. This style is simple, and each piece is easy to update.

When values change together or belong together (a form with many fields, coordinates, a payload), one object is neater:

App.jsx
JSX
function App() {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });

  return (
    <div>
      <p>x: {position.x}, y: {position.y}</p>
      <button onClick={() => setPosition({ ...position, x: position.x + 10 })}>Move right</button>
    </div>
  );
}

Because the setter replaces the value, you must copy the other fields with the spread operator. Forgetting that is the classic bug; see Updating Objects in State.

How to choose

QuestionAnswer suggests
Do the values always change together?One object
Are they unrelated (a name and a dark-mode switch)?Separate states
Do you update one at a time, often?Separate states are simpler
Does one field’s change depend on another?An object or useReducer
Will you send them together to a server?An object is convenient

Do not duplicate information

Keep state minimal. These three would be a mistake:

App.jsx
JSX
const [items, setItems] = useState([]);
const [itemCount, setItemCount] = useState(0);        // duplicate! use items.length
const [hasItems, setHasItems] = useState(false);      // duplicate! use items.length > 0

Update one and forget the others, and your screen lies. Calculate items.length instead. See Derived State.

Beware states that can contradict each other:

App.jsx
JSX
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
// Possible but invalid: isLoading and isError both true

One state with a named value prevents impossible combinations:

App.jsx
JSX
function App() {
  const [status, setStatus] = React.useState("idle"); // "idle" | "loading" | "success" | "error"

  function start() {
    setStatus("loading");
    setTimeout(() => setStatus("success"), 1000);
  }

  return (
    <div>
      <p>Status: {status}</p>
      <button onClick={start} disabled={status === "loading"}>Start</button>
    </div>
  );
}

A single status string can only be one thing at a time. This is used constantly with data fetching; see Loading States.

When it gets complicated: useReducer

If you have many related states and many ways to change them, move the logic into a reducer with useReducer, which keeps all the update rules in one function: Reducers and useReducer.

Key points

  • Use separate useState calls for unrelated values; use an object for values that belong and change together.
  • Never store values you can compute from other state.
  • Prefer one status value over several booleans that could contradict each other.