Reputation: 67
This createStore function takes the reducer functions but I don't really understand what is going on, How does it know what is the current state of the counter when we do store.getState(), what I know that the createStore() will return an object of functions but I don't understand how they work. Also, why we need the Listeners array I know someone explained that but I am looking for an easier example, I would appreciate if someone explained what that array will have and why we unsubscribe those listeners at the end.
I would really apperciate also if someone explained to me how to debug that code, I keep getting empty values in Chrome Debugger.
Last question, how does just passing the counter function makes it aware of it's state. I don't see any assignment like state = state
inside the reducer function itself.
Thank you so much in advance.
const counter = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
};
};
dispatch({});
return { getState, dispatch, subscribe };
};
const store = createStore(counter);
const render = () => {
document.body.innerText = store.getState();
};
store.subscribe(render);
render();
document.addEventListener('click', () => {
store.dispatch({ type: 'INCREMENT' });
});
Upvotes: 3
Views: 64
Reputation: 138367
How does it know what is the current state of the counter when we do
store.getState()
?
It is stored in the state
variable. Initially it is undefined
, and whenever you call dispatch
it will call the passed reducer and derive a new state. To get the initual state, it does:
dispatch({});
which will then call the reducer as:
state = reducer(/*state: */ undefined, /*action: */ {}) /*0*/
that will enter the default branch of the switch, and will return 0, therefore state
is 0 from now on. If you call dispatch again, like:
dispatch({ type: "INCREMENT" });
Then the reducer gets called again, but this time enters another bracnh of the switch, the state gets increased:
state = reducer(/*state:*/ 0, /*action:*/ { type: "INCREMENT" }) /*1*/
Also, why we need the Listeners array?
Because multiple parts of your page might need to update whenever a certain state changes. Therefore you can attach multiple listeners to it, that then get called when the state updates.
why do we unsubscribe those listeners at the end?
Because there are cases where the part of the page that the listener is updating is gone, and then it makes little sense to still update it, which would just be a waste of computational time. Through unsubscribing you can remove the listener, and therefore updates won't happen anymore..
how does just passing the counter function makes it aware of it's state ?
It doesn't. As shown above, the reducer
(counter
in this case) gets called with an empty action, which will then result in the initial state.
I would really apperciate also if someone explained to me how to debug that code
I'd place a few breakpoints, for example in the first line of count
, dispatch
, the render
function and the onClick handler, then reload the page to see that it calls count
from within dispatch
, then every time you click on the page, it will traverse the code like this onClick -> dispatch
-> count
-> render
.
Upvotes: 4