Store subscriber limits: is reentrant dispatch during notification supported?
0 reputation · 08 May 2023, 23:52 UTC
0 reputation · 08 May 2023, 23:52 UTC
Redux core notifies every registered store.subscribe listener after each dispatch, even when a reducer returns the identical state reference. Some listener designs react to a state change by dispatching a follow-up action, which means calling store.dispatch while the store is still walking its notification list.
The public subscriber contract does not clearly state whether this reentrant dispatch is a supported use of the API or an implementation detail. The concerns are concrete: the ordering of listeners that have not yet been notified, whether those pending listeners observe the newer state produced by the nested dispatch, extra notification passes, and how middleware such as thunk or saga middleware behaves when dispatch is reentered.
configureStore default middleware compared with a plain createStore setup?34775 reputation · 09 May 2023, 09:56 UTC
Yes. Redux core guarantees that calling store.dispatch() from within a store.subscribe listener is a supported, synchronous operation. The original notification loop pauses, the nested dispatch runs its own full cycle (reducer execution + subscriber notifications), and only after that does the outer loop resume.
state.store.dispatch(B).state is updated again, and all listeners are queued for a second notification cycle.subscribe registration.Redux Toolkit’s configureStore uses the same core createStore implementation, so the re‑entrant behaviour is identical. Middleware that is synchronous (e.g., thunk when used with immediate actions) participates in the same call stack. If a middleware performs asynchronous work (e.g., a saga that yields a promise), the nested dispatch occurs outside the current call stack and the outer notification loop may continue before the async side‑effect completes.
// Create a store
const store = createStore(reducer);
// Register listeners
store.subscribe(() => console.log('Listener A start', store.getState()));
store.subscribe(() => {
console.log('Listener B start', store.getState());
store.dispatch({type: 'INNER'});
});
store.subscribe(() => console.log('Listener C', store.getState()));
// Dispatch the outer action
store.dispatch({type: 'OUTER'});
Observe that the console logs show Listener B’s inner dispatch completing before Listener C runs, and Listener C sees the state after the inner dispatch.
Re‑entrant dispatch is a deliberate part of Redux’s synchronous architecture. It preserves listener ordering, ensures state consistency, and behaves the same whether you use plain createStore or Redux Toolkit’s configureStore. Only asynchronous middleware can break the synchronous guarantee, which is a separate concern.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.