DEV Community

Taulant Sela
Taulant Sela

Posted on

I benchmarked React Context vs Redux across three app types for my master's thesis — here's the setup (and a survey)

I built three application archetypes, each implemented twice — once with Context (multiple domain contexts + hooks) and once with Redux Toolkit — with pixel-identical UIs and shared components, so the only variable is the state layer:

  • Product catalog — read-heavy, many visible items, selective mutations (add to cart, wishlist)
  • Multi-step form — localized updates, validation, dependent fields
  • Live dashboard — multiple independent real-time data streams

Performance is measured by render counting: every component reports each render to a tiny registry, and automated benchmarks (Vitest + jsdom) replay identical interactions against both implementations.

Each app also ships with a visible render monitor, so you can watch it live:

A taste of the results: open both, click "Add to Cart" on any product, and watch the render counter — Context re-renders every visible product card; Redux re-renders exactly one. Then try the same comparison in the form app, and the story completely changes. That's the thesis in one sentence: it depends on the application type, and the dependency is measurable.

Where you come in
The benchmarks are half the story — the other half is what developers actually experience and choose. That's a short survey:

👉 Survey Link

29 questions, about 5–7 minutes, fully anonymous — no sign-in, no email, academic use only. If you've built React apps professionally or seriously as a hobby, your answers directly shape the thesis's decision guide.

Questions about the setup? Ask away in the comments.

Top comments (2)

Collapse
 
101beardo profile image
Tarun Sharma

The catalog result is the one you'll want to defend, because "Context re-renders every card, Redux re-renders one" is really monolithic-context vs selector-based store, not Context vs Redux as such. The fair Context version is either split domain contexts with a memoized value and React.memo on the leaves, or useSyncExternalStore with a hand-rolled store and selectors, which is Context-shaped distribution with Redux-shaped selectivity. Having all three in the matrix stops a reviewer saying you handicapped one side. One more measurement note: render count in jsdom is render-function calls, not commits, and a memoized leaf that re-renders to the same output bails before touching the DOM, so the counter overstates the Context case specifically.

Collapse
 
taulantsela profile image
Taulant Sela

Great perspective, I really appreciate it and I agree with most of it. It is genuinely not what the thesis set out to test, though, so let me draw the line I drew.

The question I picked was narrow on purpose: what do Context and Redux Toolkit give you out of the box, used the way each one is meant to be used, with no extra machinery bolted on to make one imitate the other. That is why manual optimization sits outside the scope on both sides. Neither implementation uses React.memo, and no memoized selectors are used on the Redux side either, so neither arm got hand-tuned. The moment I allow that on one side I have to allow it on both, and then I am measuring how much optimization effort I spent rather than what the two tools do.

On split contexts, that is already the implementation being benchmarked. The Context app has separate cart, products, wishlist and UI contexts, and the twenty-versus-one result is with that splitting in place. Splitting narrows the blast radius to the domain boundary, but it cannot give you selectivity within a domain, and that is the actual claim rather than "Context is slow."

On useSyncExternalStore, you are right and I will go further: it matches the Redux numbers exactly. I built that variant out of curiosity after your comment, and it is identical to Redux including the per-component breakdown. But notice what that arrangement actually is. The context value becomes a stable store reference that never changes, so Context's broadcast never fires, and every render decision is made by the store and its selectors. That is Context doing dependency injection while a store does the state management, which is how react-redux itself is built. It is a genuinely good pattern, and it is not the thing developers are arguing about when they ask whether they can skip Redux and just use Context.

So I would put it slightly differently than you did: it is state-held-in-context versus store-with-selectors, and I think that is exactly the Context versus Redux comparison, because that is what each one hands you by default. The variants you describe are real and worth measuring, and they go in future work alongside Zustand, which is already there for the same reason.

Thanks for pushing on this, it sharpened how I frame the scope.