Short answer
Yes — you can attribute the latency to each layer, but only if you measure them as separate store configurations rather than toggling things inside one run. Expected magnitudes, assuming a small action payload (a few hundred bytes) in a modern browser: a synchronous JSON.stringify/JSON.parse middleware typically adds on the order of 0.05–0.5 ms per dispatch; Redux DevTools, when the monitor is actually connected, adds a comparable amount because it also serializes the action and the resulting state; React 18's automatic batching changes render behavior, not dispatch cost. A batching middleware reduces per-action overhead roughly in proportion to batch size, which React 18 batching alone cannot do for Redux dispatches.
These are order-of-magnitude figures from well-established behavior, not guarantees — your numbers will scale with payload size and CPU. The point of the harness below is to replace them with your own.
The measurement setup
Build four stores with identical reducers and state shape, and dispatch the same action 10,000 times in a warm loop, timing with performance.now(). Report the median, not the mean, and discard the first ~500 iterations (JIT warmup).
const serializeMiddleware = () => next => action => {
JSON.parse(JSON.stringify(action));
return next(action);
};
function bench(store, action, n = 10000) {
for (let i = 0; i < 500; i++) store.dispatch(action); // warmup
const times = [];
for (let i = 0; i < n; i++) {
const t0 = performance.now();
store.dispatch(action);
times.push(performance.now() - t0);
}
times.sort((a, b) => a - b);
return times[Math.floor(n / 2)]; // median
}
Configurations: (1) bare createStore, (2) applyMiddleware(serializeMiddleware), (3) bare store with the DevTools enhancer enabled and the extension panel open, (4) middleware + DevTools. The middleware-only cost is (2) − (1); the DevTools-only cost is (3) − (1). Note that with Redux Toolkit's configureStore, DevTools are on by default in development — use the devTools: false option or plain createStore to get a clean baseline.
What each layer actually costs
The middleware cost is just the serialization of the action — it grows roughly linearly with payload size, so repeat the test with your real action shapes, not a toy {type: 'INC'}. DevTools overhead is different in kind: it serializes the action and the lifted state per dispatch, so its cost scales with your store size, and it largely disappears when the extension is not connected. That asymmetry matters: if your production users don't run DevTools, only the middleware cost ships.
Batching vs. React 18
React 18's automatic batching (via createRoot) coalesces the React re-renders triggered by consecutive store notifications — it does nothing to the dispatch path itself. If your latency is measured as dispatch-to-reducer-complete time, React 18 changes nothing; if it's dispatch-to-paint, it helps. A batching enhancer/middleware (e.g., redux-batched-actions or the batched-subscribe pattern — community packages, not Redux core) collapses N dispatches into one notification and one serialization pass, so for bursts of high-frequency dispatches it reduces per-action overhead far more than React batching does. Measure it with bursts of 100 actions flushed together and compare per-action medians.
Caveats
Measure in a production build — development builds of Redux add dev-only checks (action serializability middleware in RTK, frozen state in some setups) that can dwarf your custom middleware's cost. Keep the tab foregrounded and CPU throttling off. One detail that would change the recommendation: whether your observed latency is dispatch-to-reducer or dispatch-to-render — if it's the latter, the fix is batching notifications, not trimming middleware.