# redux-sac ## Slice redux objects (reducers, middleware, ...) ### `subReducer(key, reducer, additionalKey, ...)` Creates a wrapper reducer that calls `reducer` on the sub-state specified by `key`. Key can go in different formats, see `deepGetOrNil` below. Rest of the state is left untouched. ```js const r = subReducer("persons", personReducer); r({persons: ["John", "Jill"], cars: ["Honda"]}, action); // => { // persons: personReducer(["John", "Jill"], action), // cars: ["Honda"] // } ``` Respects redux convention that if no change was made, the identical object should be returned. So in previous case, if `personReducer` would return the identical array, `r` would return the state object it was passed in. If persons were deeper in hierarchy, it could have been created as `const r = subReducer("files.persons", personReducer);` for example. You may pass additional keys as addition arguments. In that case, additional parts of state will be fetched and passed to a sub-reducer: ```js const r = subReducer("persons", personReducer, "assets.cars"); r({persons: ["John", "Jill"], assets: {cars: ["Honda"]}}, action); // => { // persons: personReducer(["John", "Jill"], action, ["Honda"]), // assets: {cars: ["Honda"]} // } ``` This technique is mentioned in Redux docs, in "Beyond combineReducers" page. ### `subMiddleware(key | selectorFn, middleware)` Creates a wrapper middleware on the sub-state specified by `key` or the selector function `selectorFn` by decorating `getState` part of the passed arg. The `key` can have different format, see `deepGetOrNil` below. Rest of the passed arg is left untouched. ```js const r = subMiddleware("persons", ({getState}) => next => action => { console.log(JSON.stringify(getState())); return next(action); }); const altR = subMiddleware(state => state.persons, ({getState}) => next => action => { console.log(JSON.stringify(getState())); return next(action); }); // use r or altR in creation of store store.getState(); // => {persons: ["John", "Jill"], cars: ["Honda"]} store.dispatch({type: "any"}); // console => ["John","Jill"] ``` If persons were deeper in hierarchy, it could have been created as `const r = subMiddleware("files.persons", ...);` for example. You can use `subMiddleware` to sub-state anything getting one parameter in which one of the properties passed is `getState` function; it is not special-case for middleware. For example, it is usable for wrapping `redux-effex` effect function. ### `subEffex(key | selectorFn, effects)` Creates a wrapper around each element of the effects array on the sub-state specified by `key` or by selector function `selectorFn` by decorating `effect` function with `subMiddleware` and returns the array of the wrapped effects. ```js const effects = [{ action: "foo", effect: ({getState}) => { console.log(JSON.stringify(getState())); } }]; const e = subEffex("persons", effects); const altE = subEffex(state => state.persons, effects); // use e or altE in creation of store store.getState(); // => {persons: ["John", "Jill"], cars: ["Honda"]} store.dispatch({type: "foo"}); // console => ["John","Jill"] ``` ## Compose ### `composeReducers(reducer1, reducer2, ...)` Creates a wrapper reducer that calls passed reducers one after another, passing intermediate states. and returning the result of the last one. Useful to "concatenate" a few `subReducer`s. like: ```js composeReducers( subReducer("files.persons", personReducer, "assets.swag"), subReducer("files.clients", clientReducer, "news"), subReducer("assets", assetReducer), baseReducer ) ``` ## Redux helpers ### `typedAction(type, [fn])` This creates an action creator function that amends existing `fn` by: - adding a `type` property to the result, as well as - adding a `TYPE` property to action creator itself. So for example: ```js export const answerQuestion = typedAction("answer question", (index, answer) => ({ payload: {index, answer} })); ``` allows you to call `answerQuestion(2, "Albert Einstein")` to create `{type: "answer question", payload: {index: 2, answer: "Albert Einstein"}}`; but it also allows you to use `case answerQuestion.TYPE:` in your reducer, since `answerQuestion.TYPE === "answer question"`. IOW, this removes the two-space problem of having `const FOO_BAR_TYPE` as well as `fooBar` action creator. In case you don't pass the `fn` argument, the action creator only creates `{type}`.