_a Redux like system: using ES6 Generators and vanilla JS ! :) - chapter 1
Tags: es6, beginners, tinker, javascript
Published: 2023-10-22 17:01:10

#Intro

Let's keep it simple, what does a redux like state model consist of ?

> 🎚️ _A central state_ 
> 🎚️ _A message bus_ 
> 🎚️ _A function which updates the state based on the messages received via message bus_ 
> 🎚️ _A method on the state to get the current values_

**Roughly It works like this 🧠🧠🧠**

- `step 1` initialize the state with the starting values
- `step 2` inform all the components in the environment about the message bus
- `step 3` let components read values using the method available on the state
- `step 4` let components send messages in an agreed-upon format using the bus and update the state

>_Now we can make any sophisticated state management system keeping the above four as our base building blocks_
>_Also any primitive or a pre-baked language feature which can be used to achieve all the four above, can be used to create a Redux like system_

---

##Generators give us most of the above four

- Best thing about a generator is that it can be paused in between it's execution
- Just before the pause it has the ability to send the message to the scope, using the object produced by the generator function
- The scope using the generator object can unpause the generator and also can send a message back to it at the same time

---

##Inner workings of a Generator

- when you call the Generator function it returns an object, semantically called an `iterator`, however Generator's function body is not executed on this call
- The Generator's function body can execute via the `iterator` object
- Generator's function body is able to communicate with the outer scope with the help of `yield` statements
- `Iterator` object has a `next` method which is used to unpause the Generator and execute it's function body  

#### Little code snippet will help understand the basics of Generator

```javascript

function Gen*(){
   //1.
   const foo = yield "message from the generator";
   //2.
   console.log(foo);
   //3.
   yield ({bizz: "we can return any valid type"});
};

const iterator  = Gen();

/*
first call to the `next` method will 
kickstart the execution of the Generator's
function body and automatically pause 
at the first `yield` statement at line no 1.

Also before the pause the function body 
will return the value guarded by the 
`yield` statement. In the above case it is
"message from the generator" returned wrapped inside an 
object. This object has the structure 
{
value: <value guarded by the yield statement>, 
done: <boolean value, indicating end of execution of
Gen function body>
}
*/

const message = iterator.next();
console.log(message);
/* 
this will print an object 
{
  value:"message from the generator",
  done: false
}
*/

/*
now we can unpause the generator function body with 
another call to `next` on the `iterator` object. 
Also on this call we can send a message 
back to the Generator function body 
as an argument to the `next` method. 
*/

//4.
const message_from_iter = 
     iterator.next("message from the calling program");
//5.
console.log(iterator.next());

/*
The above line will pass the message back to the 
`yield` statement at line no 1.
Which then is assigned to `const foo` 
and printed at line no 2.

Then Gen function body pauses at line 3, after
passing the value guarded by the yield statement,
wrapped in an object. Structure of the is object
is again 
{
  value: { bizz: "we can return any valid type" }
  done: false;
}

At line 4 it is assigned to `const message_from_iter`.

At line 5 we again call iterator.next to reach the end
of Generator's function body.
This time the object returned by the call is 
{
   value: undefined,
   done: true,
}
*/
```

>`The above snippet is an introduction to Generator's working and represents sufficient enough Generator api which can be used to construct a Redux like system`


_______

####Before we go any further lets go through the requirements again

> 🎚️ _A central state_ 
> 🎚️ _A message bus_ 
> 🎚️ _A function which updates the state based on the messages received via message bus_ 
> 🎚️ _A method on the state to get the current values_

lets address each requisite one by one using small code snippets

 >***A Central State***

We will use a POJO ( plain old javascript object ) to represent our state, declared inside the function body of the
generator

```javascript
function* Gen(){
   //1.
   const centralState = {};

}
```
_closure of the Generator's function body will preserve the state for the lifetime of the `iterator` produced by calling the Generator function_


---

>***A Message Bus***

A message bus is a system of passing messages to and fro from the central state to the outside environment 

_We can use `iterator.next()` to send the message in and `yield` to send the message out from the Generator function body's scope. `And these two api primitives will constitute the essential parts of our message bus`_

```javascript
function* Gen(){
   const centralState = {};
   const messageIn = yield "message from the generator";
}

//1.
const iterator = Gen();



/*
line no 2. will kickstart the Generator 
function body and pause at first yield 
after receiving message from the generator
*/

//2.
const messageOut = iterator.next();

/*
 line 3. will send the message back to 
 the Generator's function body scope at 
 the currently paused `yield` and gets
 assigned to `messageIn` identifier 
*/

//3.
iterator.next("message sent to Generator");

```
---

_`I present you with the code which explains the idea of how it can be done, in the next part of this article we look into the same code with some sugar syntax on top to make usage by the client code cleaner`_


```javascript


function reducer (message, state){

const {type, value} = message;
let newState = {...state};
  switch (type){
    case "init_todo": {
      newState = { ...newState, todoList: [] };
      break;
    }
    case "add_item_todoList": {
      newState = {...newState, todoList: [...newState.todoList, value]};
      break;
    }

  }

return newState;

}


/*🎈🤡 The generator function: the saviour*/
function* Gen(){
   console.log("\n this message will print only on the first call to `iter.next`");
    /*
     * a simple state 🌈
     * */ 
   let centralState = {};
   
   /* 💡first time when function halts at yield , it also returns this message to calling scope*/ 
   const messageIn = yield "hi! i am the message from the generator: the first one";
  
   /* 🌟this is function the client code can use to read a given property on the state*/ 
   const getStateSlice = (propertyName) => JSON.parse(JSON.stringify(centralState[propertyName]));
   
   /* 💎using a plane function called reducer to process the incoming message and redefining the state */ 
   centralState = reducer(messageIn, centralState);
  
 /* 🔄 using a loop like an event-loop to process the messages received */ 
  while(true) {
    const clientMessage = yield getStateSlice;  
    centralState = reducer(clientMessage, centralState);
  } 

}

//1.
const iterator = Gen();

/*
line no 2. will kickstart the Generator 
function body and pause at first yield 
after receiving message from the generator
*/

//2.😏 Initialze local variables and whatever you like on the first call to `iterator.next`
console.log("😏 For the first time `next` is called on the iterator object, we can use this call to initialize things");
const messageOut = iterator.next();

console.log(`message received  🍰 from the generator ${messageOut.value}`);

/* 🎉 passing message using the iterator and getting a function in return which can read on the encapsulated state */
let {value: readProperty, done: _ } = iterator.next({ type: "init_todo", value:null });
console.log("lets see what we 🍰 get in return", readProperty("todoList"));

/* 🔮 adding a first value in our todo list where state is powered by a generator and then checking if it has been added */
let {value = readProperty, done =  _ } = iterator.next({type: "add_item_todoList", value: "install headSpace"});
console.log("lets check again what did we 🍰 get in return", readProperty("todoList"));

```