Redux Compose

Higher Order functions to aid in composing Redux Reducers.

Table of Contents

Motivation

While redux provides a clean separation of concerns by distinguishing actions and reducers the examples given don't provide a lot of examples on how to break down complex reducers into distinct and testable components. The provided combineReducers can act as a starting point but doesn't scale up to lots of reducer logic.

This library exports a set of higher order functions that allow you to write very focused reducers and compose them into a single larger complex reducer. Additionally by leveraging these helper functions we're able to gain large amounts of type inference in order to reduce some of the typing overhead with Redux

Installation

npm add --save redux-compose

yarn add redux-compose

Usage

All functions are exported as a ESModule from the index file, or as ESModules from independent files.

import { composeReducers } from ' redux-compose ' ; import { composeReducers } from ' redux-compose/compose-reducers ' ;

API

Given a set of reducers returns a reducer. When invoked each of the given reducers are called in order with the action and the state that is returned from the previous reducer.

composeReducers is the primary composition function, and should be the main means of combining specific reducers to form a larger reducer. Other functions provide a set of action and state filtering operations.

The reducers are called in left-to-right order so the 2 pieces of code are equivalent:

import { composeReducers } from ' redux-compose/compose-reducers ' ; ... ;

...

forPath creates a reducer that targets a sub section of the state. The first argument is a path expressed as an array of string, numbers, or functions that translate an action into a string or number. The second argument is a reducer that will be called with the state at the given path.

forPath will try to create intermediary states if the path crosses an undefined value. If the path part is a number the intermediary state will be a empty array, otherwise it will be a empty object.

When updating values in an array forPath may create a sparse array.

Example:

import { forPath } from ' redux-compose/for-path ' ; interface State { ; } interface AddOneAction { ; ; } ;

Given a typeString or typePredicate, or array of typeStrings or typePredicates and a reducer return a reducer that is only invoked when the action matches one of the types.

If the type is provided as a string the string is used to match the type field on the action. If the type is provided as a function the action is passed to the function.

To match on multiple types an array of either strings or functions can be provided, in which case they act as an "or" match on the action.

Example:

import { ofType } from ' redux-compose/of-type ' ; ; ; ; ; ;

Given a default state and a reducer returns a reducer which invokes the provided reducer using the default state if the state is undefined .

Example:

import { withDefault } from ' redux-compose/with-default ' ; interface State { ; } ;

If no reducer argument is provided to withDefault then a identity reducer ( state => state ) is used. This is useful when paired with composeReducers to set an initial state for a series of reducers.

import { composeReducers } from ' redux-compose/compose-reducers ' ; import { withDefault } from ' redux-compose/with-default ' ; interface State { ; } ;

Contributing

Building Locally

We use yarn and nvm to ensure consistent build environments.

run tests using jest yarn test

run gulp build yarn gulp

format code yarn format

lint code yarn lint

While all contributes are welcome the following rules will help you get your contributes accepted faster:

PRs should reference a specific issue. If no issue exists for the desired changes please create one in order for us to have a meaningful discussion about the requested change.

PRs should have a clean commit history. You may be asked to rebase and make changes to your PR in order to help us maintain a clean commit history.

PRs should include tests, examples, and documentation. PRs without tests will be rejected, new features, should have documentation and examples added for them.

PRs should include correct Typescript types. Typescript support is an important part of redux-compose so any new features must have full typing.

License

MIT