Jason
Jason

Reputation: 67

Can someone explain the createStore function and how just passing the counter function to it makes it aware of the state?

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

Answers (1)

Jonas Wilms
Jonas Wilms

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

Related Questions