DEV Community

Timothy Fosteman
Timothy Fosteman

Posted on

Basics in Redux

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
Enter fullscreen mode Exit fullscreen mode

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'
                            }
    }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

The following is allowed, due to concat which concatenates immutable store to the payload.

    (state, action) => state.concat(action.payload)
Enter fullscreen mode Exit fullscreen mode

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;
        }
    }
Enter fullscreen mode Exit fullscreen mode

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 
                );
    }
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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

Top comments (4)

Collapse
 
sebbdk profile image
Sebastian Vargr

The irony of redux is that it is very hard to reduce the explanation of how it works.

Collapse
 
fosteman profile image
Timothy Fosteman • Edited

Nevertheless, it should be said that implementation is rather trivial

Collapse
 
sebbdk profile image
Sebastian Vargr

Yes, it’s very reduced’ in size and complexity.

I will stop now... :D

Collapse
 
anshulnegitc profile image
Anshul Negi • Edited

Thanks ...really helpful article
The flowchart solely explains how redux works.