paint-brush
How To Implement Simple State Container From Scratchby@kliukovkin
6,592 reads
6,592 reads

How To Implement Simple State Container From Scratch

by Georgii KliukovkinJune 9th, 2021
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Redux is about functional programming, so we will use pure functions and immutability. We separate representation and data layer, move the state from component to separate place. Clicking any button will trigger action. So we have an action and now we need to change the state of our application. We now have on direction, data down and actions up. We need to use the observer pattern to notify multiple objects about any events that happen to the object they’re observing. It's better to know what does observer pattern does.
featured image - How To Implement Simple State Container From Scratch
Georgii Kliukovkin HackerNoon profile picture

Let's imagine that we have a component, a simple counter. The counter has a state and two buttons to manipulate with this state. We also have a function to render the state.

And here we have two problems:

  • representation layer and data layer are mixed. So, if you want to change one of them, you will touch both. It is a violation of SRP.
  • it is hard to support and maintain logic between components that have local states. Scalability problem arises.

To solve these problems we will use the FLUX approach which essentially means "Data downAction up". Clicking any button will trigger action. So we have an action and now we need to change the state of our application. But how we suppose to do that? 

Redux is about functional programming, so we will use pure functions and immutability. Functions, that will change our state we will call reducer. It will get the current state and action as an argument and will return to the new state. The function will look like this:

function reducer(state, action) {
    switch (action.type) {
	case 'INCREMENT':
            return state + 1;
	case 'DECREMENT':
	    return state - 1;
        default:
            return state;
    }
}

Now we need to create our store. Let's right the new function and call it

createStore
.

function createStore(reducer) {
    let state = 0;
    return {
        getState(){
            return state;
        },
        dispatch(action){
            state = reducer(state, action);
        }
    }
}

Before we can move on, it's better to know what does observer pattern does. Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing. Let's add this logic to our function:

function createStore(reducer) {
  let state = 0;
  const observers = [];
  return {
      getState(){
          return state;
      },
      subscribe(observer){
          observers.push(observer);
      },
      dispatch(action){
          state = reducer(state, action);
          observers.forEach(cb => cb());
      }
  }
}

And that's it! We separate representation and data layer, move the state from component to separate place, dependencies now have on direction, data down and actions up.