Redux

Redux general information

Redux is a predictable state container for JavaScript apps. It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger. We use redux module for React - https://github.com/reactjs/react-redux

Actions in redux

**Actions** are payloads of information that send data from your application to your store. They are the *only* source of information for the store. You send them to the store using [`store.dispatch()`](../api/Store.md#dispatch).

Here's an example action which represents adding a new todo item:

const ADD_TODO = 'ADD_TODO'
{
type: ADD_TODO,
text: 'Build my first Redux app'
}

Actions are plain JavaScript objects. Actions must have a `type` property that indicates the type of action being performed. Types should typically be defined as string constants. Once your app is large enough, you may want to move them into a separate module.

Action Creators

**Action creators** are exactly that—functions that create actions. It's easy to conflate the terms “action” and “action creator,” so do your best to use the proper term.

In Redux action creators simply return an action:

For this we use createAction from redux-actions

const addTODORequest = createAction(ADD_TODO);
And for add logic actions to 'action' we need create Epic function.
	const addTODOEpic = (action$, store) =>
  action$.ofType(ADD_TODO)
    .map(({ payload }) => {
      // TODO something
      return payload
    });

This makes them portable and easy to test.

Actions describe the fact that something happened, but don't specify how the application's state changes in response. This is the job of reducers.

	function reducer(data = {}, action) {
		switch (action.type) {
			case ADD_TODO:
				return someFunctionSetToData(data, action.data);
			default:
				return data;
		}
	}

Source Code

`fetch-todo.duck.js`

/*
* action types
*/
export const ADD_TODO = 'ADD_TODO';
export const ADD_TODO_SUCCESS = 'ADD_TODO_SUCCESS';
export const ADD_TODO_FAILURE = 'ADD_TODO_FAILURE';

/*
* actions
*/
export const fetchAddTODO = createAction(ADD_TODO);
export const fetchAddTODOSuccess = createAction(ADD_TODO_SUCCESS);
export const fetchAddTODOFailure= createAction(ADD_TODO_FAILURE);

/*
* epics
*/
export const fetchAddEpic = (action$, store) =>
  action$.ofType(ADD_TODO)
    .merge(({ payload }) => fetchAddTODOSuccess({
    	data: payload
		}))
		.catch(error => Observable.of(fetchAddTODOFailure(error)));
/*
* reducer
*/
export default function reducer(data = {}, action) {
	switch (action.type) {
		case ADD_TODO:
			return someFunctionSetToData(data, action.data);
		default:
			return data;
	}
}

Usage within PulseTile

We are using redux architecture and especially reducers and actions in order to unify the data flow within the project. The goal we are achieving this way is, basically, the unification of the application's state and data flows in terms of responses we're proceeding on the front-end. You can see the examples of Main reducer file, where all the other reducers are included. As well, module-specific duck file , where the state management is handled.

Q: Why was Redux chosen?
  • An acceptable choice, with equal benefits to React's state management system
  • Not really gaining benefits at this stage, but as the system grows it could prove very useful
Q: What benefits are gained from using Redux

A: There are a couple of them, and the main ones:

  • Scalability when state becomes complex
  • A robust platform for future development
Q: Do we know what the driver choose Redux? It seems we are tied to that technology now, so although it may be a great fit we are still unclear what drove that decision and whether it was the right one.

A: It seems the Redux code is clearly delineated from the React code, meaning that we aren't completely tied to the technology choice if it proves to be more of a hindrance than a benefit.