A tiny store
Implement createStore(reducer, initialState) with getState(), dispatch(action) and subscribe(listener). dispatch computes the next state with the reducer, stores it, and then calls every listener. subscribe returns a function that removes that listener. A listener that unsubscribes itself during a dispatch must not make another listener miss that dispatch. In the tests the reducer is a counter (inc, dec); a listener named A logs [A, state]; A! also unsubscribes itself.
Start from
function createStore(reducer, initialState) {
// Return { getState, dispatch, subscribe }.
}Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1
State and the list of listeners live in the closure.
Hint 2
In dispatch, update the state before calling listeners, and loop over a copy of the list.
Hint 3
subscribe returns a function that filters that listener out.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
JavaScript
function createStore(reducer, initialState) {
let state = initialState;
let listeners = [];
return {
getState: () => state,
dispatch(action) {
state = reducer(state, action);
for (const listener of [...listeners]) listener();
return action;
},
subscribe(listener) {
listeners.push(listener);
return () => {
listeners = listeners.filter((item) => item !== listener);
};
},
};
}What an interviewer looks for
Redux, Zustand and useSyncExternalStore all have this shape. Writing it shows you know what a store is under the library.