DEV Community

Muhammed Fayaz T S
Muhammed Fayaz T S

Posted on

Proxy State in React: What It Is and How It Differs from useState

When building React apps, state management is unavoidable. Most of us start with useState, and for good reason — it’s simple, predictable, and built into React.

But as applications grow, you may hear about something called “proxy state.” Libraries like MobX and Valtio often come up in this context.

So what exactly is proxy state?
How does it differ from useState?
And when should you care?

Let’s break it down.


Understanding useState first

useState works on a snapshot model.

const [count, setCount] = useState(0);
setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

Each update:

  • does not mutate existing state
  • replaces it with a new value
  • triggers a component re-render

With objects, this usually means copying:

const [user, setUser] = useState({ name: "Alex", age: 20 });

setUser(prev => ({
  ...prev,
  age: 21
}));
Enter fullscreen mode Exit fullscreen mode

React only knows something changed because the reference changed. It does not track which property changed.

This approach is:

  • predictable
  • aligned with functional programming
  • extremely well optimized

But it can get verbose and inefficient in large applications.


What “proxy state” means

React itself does not provide proxy state.

The term usually refers to state management libraries that use JavaScript Proxies under the hood.

Examples:

  • MobX
  • Valtio
  • reactive store systems inspired by Solid or Vue

A JavaScript Proxy can intercept operations like:

  • reading a property
  • writing a property

This allows libraries to automatically track:

  • what parts of state a component used
  • what exactly changed

So instead of replacing state, you mutate it directly.

state.count++;
state.user.name = "Fayaz";
Enter fullscreen mode Exit fullscreen mode

The proxy detects the mutation and notifies only the components that depend on those properties.


The mental model shift

The biggest difference is how you think about state.

useState → snapshot-based

  • state is immutable
  • updates replace values
  • re-render happens at the component level

Proxy state → reactive objects

  • state is mutable
  • updates are property-level
  • re-render happens at the usage level

You stop thinking about “setting state” and start thinking about “changing state.”


Example: same logic, two styles

With useState

const [cart, setCart] = useState({ items: [], total: 0 });

function addItem(item) {
  setCart(prev => ({
    ...prev,
    items: [...prev.items, item],
    total: prev.total + item.price
  }));
}
Enter fullscreen mode Exit fullscreen mode

You must:

  • copy objects
  • replace state
  • manually keep values in sync

With proxy state (conceptual)

cart.items.push(item);
cart.total += item.price;
Enter fullscreen mode Exit fullscreen mode

The proxy system:

  • detects the mutation
  • tracks dependencies
  • re-renders only what actually used cart.items or cart.total

Your code feels closer to plain JavaScript.


Dependency tracking: the real power

React with useState doesn’t know which properties you accessed.

const name = user.profile.name;
Enter fullscreen mode Exit fullscreen mode

If any part of user changes, the entire component re-renders.

Proxy-based systems track access at runtime:

  • Component A reads user.name
  • Component B reads user.age
  • Only the component that depends on the changed property updates

This is called fine-grained reactivity, and it’s the main technical advantage of proxy state.


Performance implications

  • useState → coarse-grained updates
  • Proxy state → fine-grained updates

In large apps with deeply nested global state, proxy systems can significantly reduce unnecessary re-renders.

That said, useState is:

  • simpler to debug
  • fully aligned with concurrent React
  • more than fast enough for most UI state

When proxy state shines

Proxy state is especially useful when:

  • your app has a large global store
  • many components read tiny slices of state
  • state is deeply nested
  • performance tuning becomes difficult
  • you prefer mutation-style APIs

When useState is still the best choice

Stick with useState when:

  • state is local to a component
  • you’re managing UI concerns (forms, modals, toggles)
  • you want to rely only on core React APIs
  • explicit, predictable updates matter most

For most UI logic, useState is still the cleanest solution.


Proxy state is not Immer

A common confusion: Immer also uses proxies, but it does not create reactive state.

setState(draft => {
  draft.count++;
});
Enter fullscreen mode Exit fullscreen mode

Immer lets you write mutable code while still producing an immutable snapshot.

Proxy state libraries keep the proxy object alive and make it reactive.


Final takeaway

Proxy state differs from useState because it uses JavaScript Proxies to:

  • track property access
  • detect mutations
  • trigger fine-grained updates

useState works by replacing values and re-rendering components.
Proxy state works by mutating objects and letting a reactive system decide what should update.

Neither is better.
They solve different problems at different scales.

Top comments (0)