📜 ⬆️ ⬇️

Redux store: horizontal expansion

Redux When an application using Redux grows to a sufficiently large size, the number of states increases many times. For the separation of reducers into logical units, an approach of combining them using combineReducers is used . This solution allows you to expand the store vertically. But there are times when this separation may not be enough. For example, one of the levels carries a composite logic, which it would also be nice to divide (or as one of the famous people said: “Enhance!”). But this approach is not in the Redux API. And the search for a solution to this issue did not give anything either (maybe I looked badly). Therefore, I developed my approach to expanding along the “horizontal” Redux Store.

I want to introduce you to my project , which allows you to implement this approach.

Using


1) First, at the level 1 level reducer, we include the library itself:
')
import {stateCombine, runCombine, getInitialState} from "redux-combine-deep-props"; 

2) Connect the reducer for the second level:

 import level2Module from "./reducer-level-2"; 

3) Form the initial values ​​for the first level:

 let initialState = { propLevel1: ..., ... propLevelN: ... }; 

4) Create a combination object:

 let combinations = { <name prop>: { module: level2Module } }; 

where we set the name of the future section of the name prop , and for it - a reducer of this level, as well as a set of types of eshenov for triggering changes to the state of this level .

5) Create a handler function for the current state:

 let combineDeepProp = stateCombine(combinations); let combine = runCombine(combinations, combineDeepProp); 

6) To handle the initial values ​​of all levels, create a combined initial state.

 const combineInitialState = getInitialState(combinations, initialState); 

7) In the export-reducer function, we use the combined initial state , and in its body, strictly before any state change, we start the handler of all combinations, which changes the current state as necessary, if the current action type matches the specified ones:

 export default function level1Module (state = combineInitialState, action) { ... let newState = combine(state, action); ... switch (action.type) { case "....": newState = { ...newState, ... }; break; ... }; ... return newState; }; 

8) The module of the second level is made out according to the standard scheme, taking into account that the state in it is presented in the context of this level:

 let initialState = { ... }; export default function search(state = initialState, action) { ... switch (action && action.type) { ... }; }; 

but with one difference - there should be a check for undefined current action . Made for setting the initial state on the first pass in the getInitialState method.

Conclusion


This approach allows in the recursive mode to expand to infinity the current level and "vertical", due to the use in combinations of more than one object:

 let combinations = { <name prop1>: { module: level2Module1 }, ... <name propN>: { module: level2ModuleN } }; 

and horizontally, by using the approach described above on each of the 2+ levels.

Sources

UPD:
Full code refactoring, thank you very much dagen , for pointing out the problem of mutability. Now the principle of use has changed a little, see p.7 and p.4 - a set of actions is now absent as unnecessary, but left the combination as an object for possible further expansion of the functional. I note that I used this approach in conjunction with PolymerJS , and then with VueJS , and used polymer-redux and vuedeux libraries for integration with Redux, respectively. And since there is a bandage on specific properties of the state, they follow the path of mutations, since it was not necessary to mutate the root state when one of the subtrees was mutated.
UPD2:
Added rollup collector to compile project

Source: https://habr.com/ru/post/335868/


All Articles