Basics in Redux
Tags: redux, explainlikeimfive, statemanagement, tutorial
Published: 2019-08-06 14:58:59

Redux adopted a handful of constraints from the Flux architecture: **Actions** encapsulate information for **reducer** to update the state deterministically. It has a singleton **Store**, indeed. Single Flux dispatcher is replaced with multiple small **Reducers** that pick up information from actions and "reduce" it ti a new state that's then saved in the **Store**. When state in the **Store** is changed the View as per **subscription** receives props.

Concept:
```
    View -> Action -> Reducer -> Store -> View
```

The name "Redux", therefore, combines two "Reduce" and "Flux". Difference is state does not live in the View anymore, it is only **connected** to the View, meaning both ends (the View and the Store) are now responsible for Action-Update-Notification uni-directional wheel.

Notably, Redux can run standalone!

## Action

Redux loves objects. And **Actions** are objects, indeed. It has an **action type** and **payload**. 
```
    {
    	type: 'set_thermostate_temp',
    	payload: {
    						id: 'basement', 
    						temprature: 24.0,
    						authorizedBy: 'Timofei Shchepkin'
    						}
    }
```
Executing this **action** will prompt *dispatch* that may alter (or not) state in the **Store**.

## Reducer

In unidirectional data flow, the View *dispatches* **actions** to **reducer**. 

By definition from functional programming, **reducer** is a pure function, hence produces deterministic results with no side effects.

**Reducer** has two inputs: state and **action**. State is the whole state object from the **Store,** the action is the dispatched object with type and optional payload. 

The Reducer *reduces* the **Store.**
```
    (state, action) => newState
```
Moreover, it harnesses immutability of the state inside **Store**. The following is incorrect, since it would mutate the previous state
```
    (state, action) => state.push(action.payload)
```
The following is allowed, due to `concat` which concatenates immutable store to the payload.
```
    (state, action) => state.concat(action.payload)
```
### Action type

I haven't mentioned type just yet. The story is when action object arrives at reducer's land, as if by a `switch` statement, the action type becomes the key to a lock (the correct reducer). If key didn't open any doors, well, state persists untouched.

Example of a *Reducer Land*
```
    function reducer(state, action) {
    	switch(action.type) {
    		case: 'set_thermostate_temp': {
    			//do some magic IOT stuff
    		}
    		case: 'toggle_window_shutters': {
    			return state.map(windows => window.id === action.id
    				? Object.assign({}, windows, {opened: !window.opened})
    				: windows 
    			);
    		}
    		default: return state;
    	}
    }
```
In `open_window_shutters` case, `map` is used to iterate over controllable windows in the basement, and toggles uniquely identified instance `on`

Functionality of `map` always returns new array, it does not mutate the previous state.

`Object.assign()` returns a new object without mutating the old object, under the hood it merges all given objects from the former to the latter into each other. If a former object shares the same property as a latter object, the property of the latter object will be used. Thus, the completed property of the updated `window` item will be the negated state of the old `window` item.

Noteworthy, actions and reducers are plain JS, no Redux magic involved so far. 

In addition, stay cool, dry - use antiperspirant - extract case branches into pure functions
```
    function reducer(state, action) {
    	switch(action.type) {
    		case: 'set_thermostate_temp': {
    			return applyThermostateTemp(state, action);
    		}
    		case: 'toggle_window_shutters': {
    			return applyWindowToggler(state, action);
    		}
    		default: return state;
    	}
    }
    function applyThermostateTemp(s, a) {
    	return state.thermostate.currentTemperature = a.temp; // IOT ~~magic~~
    }
    function applyWindowToggler {
    	return state.map(windows => window.id === action.id
    				? Object.assign({}, windows, {opened: !window.opened})
    				: windows 
    			);
    }
```
## Store

Singleton store holds one global state object. Store delegates actions to the reducer. Store triggers actions. Store updates the state and notifies subscribed components. And, en fin, it is the first library dependency to be encountered in Redux.

`import { createStore } from 'redux'`

To create a singleton instance, pass the mandatory argument - `reducer` and optional initial state

`const store = createStore(reducer, {})`

## Dispatching an **action**

`store.dispatch(action)`

## Reading global state from the **Store** 

`store.getState()`

Subscribe (and unsubscribe) to the **Store** in order to listen for updates
```
    const unsubscribe = store.subscribe(() => { 
    	console.log(store.getState());
    });
    // eventually unsubscribe
    unsubscribe();
```
# Conclusion

You know about all the basics in Redux now. A view dispatches an action on the store, the action passes all reducers and gets reduced by reducers that care about it. The store saves the new state object. Finally, a listener updates the view with the new state.

## Additional material

https://facebook.github.io/flux/
https://youtu.be/nYkdrAPrdcw?list=PLb0IAmt7- GS188xDYE- u1ShQmFFGbrk0v
https://twitter.com/dan_abramov
https://twitter.com/acdlite
https://www.youtube.com/watch?v=xsSnOQynTHs
https://www.youtube.com/watch?v=uvAXVMwHJXU