Redux ***** `Redux `__ is a Predictable State Container for JS Apps. Redux is based on *Flux* pattern which complements React's composable view components by utilizing a unidirectional data flow. Flux applications have three major parts: the dispatcher, the stores, and the views (React components). .. figure:: img/flux.jpg :alt: flux architecture :align: center :width: 400 Unidirectional data flow Redux is a simple implementation of this abstract concept- Actions Reducers Stores ======================= In this implementation a single, global, **Store** is delegated to contain all the application state. The state can be changed dispatching **Actions** to the store. Each action produces a new state (the state is never changed, a new state is produced and that is the new application state), through the usage of one or more **reducers**. **(Smart) Components** can be connected to the store and be notified when the state changes, so that views are automatically updated. .. figure:: img/redux-base.gif :alt: redux basic animation :align: center :width: 400 Basic sync flow of state evolution in redux. Actions ======= In Redux, actions are actions descriptors, generated by an action creator. Actions descriptors are usually defined by an **action type** and a set of parameters that specify the action payload. .. code-block:: javascript const CHANGE_TITLE= 'CHANGE_TITLE'; // action creator function changeTitle(newTitle) { return { type: CHANGE_TITLE, title: newTitle }; } Reducers ======== Reducers are functions that receive an action and the current state and: * produce a new state, for each recognized action * produce the current state for unrecognized actions * produce initial state, if the current state is undefined .. code-block:: javascript function reducer(state = {title: "CHANGE_ME"}, action) { switch (action.type) { case CHANGE_TITLE: return {title: action.title}; default: return state; } } Store ===== The redux store combines different reducers to produce a global state, with a slice for each used reducer. .. code-block:: javascript var rootReducer = combineReducers({ slice1: reducer1, slice2: reducer2 }); var initialState = {slice1: {}, slice2: {}}; var store = createStore(rootReducer, initialState); The Redux store receives actions, through a dispatch method, and creates a new application state, using the configured reducers. .. code-block:: javascript store.dispatch(changeTitle('New title')); You can subscribe to the store, to be notified whenever the state changes. .. code-block:: javascript store.subscribe(function handleChange() {}); .. _ref_redux_dev_tool: Redux DevTools =============== We strongly recommend the installation of `Redux DevTools `__ which brings a lot of useful features Debugger -------- It will contain the list of actions dispatched where you can see the action payload, the state diff and the final state .. figure:: img/redux_dev_tools.jpg :alt: redux dev tools :align: center Redux dev tools Time travel ----------- The DevTools allows you to do "time-travel debugging", stepping back and forth in the action history to see the entire app state and UI at different points in time. Live Editing ------------ You can dispatch you actions using the dispatcher built-in without having to trigger it from an user interaction or programmatically Redux Middleware ================ In these frameworks, a *middleware* is some code you can put between the framework receiving a request, and the framework generating a response The best feature of middleware is that it's composable in a chain. We use multiple independent third-party middleware in a single project such as: - Redux thunk (going to be fully replaced by redux-observable) - Redux Observable .. figure:: img/redux.gif :alt: redux basic animation :align: center Basic sync flow of state evolution in redux. Redux-Thunk =========== This middleware allows to perform simple asynchronous flows by returning a function from the action creator (instead of an action object). .. code-block:: javascript // action creator function changeTitleAsync() { return (dispatch, getState) => { myAsyncPromise.then( (newTitle) => { dispatch({ type: CHANGE_TITLE, title: newTitle };) }); } } This middleware is there from the beginning of the MapStore history. During the years, some better middlewares have been developed for this purpose. We want to replace it in the future with redux-observable. Redux Observable ================ This middleware provides support for side-effects in MapStore using rxjs. The core object of this middleware is the ``epic`` .. code-block:: javascript function (action$: Observable, store: Store): Observable; The epic is a function that simply gets as first parameter an ``Observable`` (stream) emitting the actions emitted by redux. It returns another ``Observable`` (stream) that emits actions that will be forwarded to redux too. So there are 2 streams: * Actions in * Actions out A simple epic example can be the following: .. code-block:: javascript const pingEpic = action$ => action$.filter(action => action.type === 'PING') .mapTo({ type: 'PONG' }); Every time a 'PING' action is emitted, the epic will emit also the 'PONG' action. Main features of Redux ====================== Single source of truth ---------------------- The global state of your application is stored in an object tree within a single store. This makes it easy to create universal apps, as the state from your server can be serialized and hydrated into the client with no extra coding effort. A single state tree also makes it easier to debug or inspect an application; it also enables you to persist your app's state in development, for a faster development cycle. Read only immutable state ------------------------- The only way to change the state is to emit an action, an object describing what happened. This ensures that neither the views nor the network callbacks will ever write directly to the state. Instead, they express an intent to transform the state. Because all changes are centralized and happen one by one in a strict order, there are no subtle race conditions to watch out for. As actions are just plain objects, they can be logged, serialized, stored, and later replayed for debugging or testing purposes. Changes are made with pure functions ------------------------------------ To specify how the state tree is transformed by actions, you write pure reducers. Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state objects, instead of mutating the previous state. You can start with a single reducer, and as your app grows, split it off into smaller reducers that manage specific parts of the state tree. Because reducers are just functions, you can control the order in which they are called, pass additional data, or even make reusable reducers for common tasks such as pagination. References ========== Here some useful links about the arguments discussed: - `Fundamentals of Redux Course from Dan Abramov `__ - `Flux `__