# Redux Preboiled

![](/files/zQrxQlZkxbfu7p6YLVav)

*Pre-cooked Redux helpers, served à la carte.*

Redux Preboiled is a collection of general-purpose [Redux](https://redux.js.org/) helper functions. It helps you reduce boilerplate when writing reducers, action creators, and tests.

* **Served&#x20;*****à la carte*****.** Each of Preboiled's helpers can be used stand-alone. Just pick and use the ones you want and ignore the rest. If your build setup does [tree shaking](https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking/), the unused helpers won't even be added to your application's build output.
* **Minimal magic.** Preboiled avoids clever "magic" tricks which minimize boilerplate at the expense of understandability. Instead, it favors simple, composable functions with easy-to-understand semantics and implementations.
* **TypeScript-friendly.** Redux Preboiled is written in [TypeScript](https://www.typescriptlang.org/). Its helpers are designed to be easy to type and amenable to automatic type inference, making it easy to write type-safe Redux code.

## A First Taste

The following snippet uses a bunch of Redux Preboiled's helpers to define a simple Redux counter module with support for `increment` and `multiply` actions. It is about half the size of the equivalent vanilla Redux code.

```js
import {
  chainReducers,
  createAction,
  onAction,
  withInitialState
} from 'redux-preboiled'

const increment = createAction('increment')
const multiply = createAction('multiply').withPayload()

const counterReducer = chainReducers(
  withInitialState(0),
  onAction(increment, state => state + 1),
  onAction(multiply, (state, action) => state * action.payload)
)

// Example usage:

import { createStore } from 'redux'

const store = createStore(counterReducer)
store.dispatch(increment())
store.dispatch(increment())
store.dispatch(multiply(2))
store.getState()
// => 4
```

* `createAction` generates various types of action creator functions with minimal cerenomy. The specified action type value is made available as an action creator property (`increment.type` and `mutliply.type` in this example), making separate action type constants unnecessary. See the [Actions](/guides/actions) guide.
* The `onAction`, `withInitialState` and `chainReducers` helpers can be combined as a less noisy alternative to the classic `switch` reducer pattern. In TypeScript, the type of the sub-reducers' `action` parameters are automatically inferred from the action creators passed to `onAction`, improving type safety and editor auto-completion. See the [Reducers](/guides/reducers) guide.

## Next Steps

The [Getting Started](/guides/getting-started) guide shows you how to install and use Redux Preboiled. Follow the links to the other guides for a tour through Redux Preboiled's helpers. You can also look at the repository's [examples](https://github.com/denisw/redux-preboiled/tree/master/examples) directory.

For reference documentation, see the [API docs](/api/api).


# Getting Started

## Installation

Redux Preboiled is published to the [NPM registry](https://www.npmjs.com/package/redux) as `redux-preboiled`. You can install it as usual via NPM or [Yarn](https://yarnpkg.com/).

```
# NPM
npm install redux-preboiled

# Yarn
yarn add redux-preboiled
```

TypeScript typings are provided out of the box - no additional typings package needed.

## Usage

Preboiled is just a collection of helper functions, so there is no required setup. Just import the helpers you need directly from the `redux-preboiled` module, for example:

```js
import { chainReducers, onAction } from 'redux-preboiled';
```

If you use a module bundler thats supports [tree shaking](https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking/) - such as [Webpack](https://webpack.js.org/) or [Rollup](https://rollupjs.org/) - only the helpers you actually use will end up in your application's build output. For instance, in a React app boostrapped with [Create React App](https://facebook.github.io/create-react-app/), this works out of the box.

## Next Steps

For a tour of Redux Preboiled, see the guides on the provided helpers for [actions](/guides/actions), [reducers](/guides/reducers) and [testing](/guides/testing).


# Actions

Defining [Redux actions](https://redux.js.org/basics/actions) commonly involves two declarations: an *action type constant* with the `type` value to use, and an *action creator* to generate actions of that type.

```js
// Without Preboiled

const INCREMENT = 'counter/increment'
const DECREMENT = 'counter/decrement'
const MULTIPLY = 'counter/multiply'

const increment = () => ({
  type: INCREMENT
})

const decrement = () => ({
  type: DECREMENT
})

const multiply = amount => ({
  type: MULTIPLY,
  payload: amount
})
```

This is a straight-forward pattern [with several upsides](https://redux.js.org/recipes/reducing-boilerplate#actions), but it's also a quite verbose one. Preboiled's [`createAction`](https://github.com/denisw/redux-preboiled/blob/master/docs/guides/createAction.md) helper, described in this guide, helps you reduce the noise while keeping the benefits. Here is the equivalent code using `createAction`:

```js
// With Preboiled

import { createAction } from 'redux-preboiled'

const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const multiply = createAction('counter/multiply').withPayload()
```

The following sections explain `createAction` and its capabilities in more detail.

## Simple Actions

The `createAction` helper allows you define an action with a single declaration, minimizing boilerplate and room for error. Given an action type value, it returns a matching action creator.

```js
import { createAction } from 'redux-preboiled'

const increment = createAction('counter/increment')

increment()
// => { type: 'counter/increment' }
```

The action type value is made available as a `type` property on the returned action creator (e.g., `increment.type` in the example above). This means you don't need to define a separate action type constant.

```js
increment.type
// => 'counter/increment'
```

The action creator also gets a `matches()` method that compares its `type` with that of a given actions, and returns true if they match. In TypeScript, this method is defined as a \[type predicate]\[ts-type-predicate], so that the compiler can narrow the type of the action in code sections where `matches()` is true:

```ts
if (increment.matches(action)) {
  // The type of `action` is `Action<'increment'>` here
}
```

These additions allow some of Redux Preboiled's other helpers to accept a `createAction` action creator in place of an action type value. For instance, `onAction` (described in the [Reducers guide](/guides/reducers)) lets you specify the action type by directly passing `increment` instead of `increment.type` or `'counter/increment'`. This is especially beneficial if you use TypeScript, where the action creator's static type is [used for automatic type inference](/api/onaction#typescript-notes).

By default, the action creators returned by `createAction` produce basic actions with nothing more than a `type`. But this can be changed, as described in the next section.

## Payload Actions

Often, you need to add extra data to actions. For these cases, `createAction` allows you to generate *payload action creators*. These take a single argument and attach it to the returned action as `payload`.

To make a payload action creator, call `.withPayload()` on an action creator returned by `createAction`:

```js
const multiply = createAction('counter/multiply').withPayload()

multiply(2)
// => { type: 'counter/multiply', payload: 2 }
```

In TypeScript, you can specify the type of the payload as a type parameter:

```ts
// TypeScript

const multiply =
  createAction('counter/multiply').withPayload<number>()
```

If you need to attach more than one value to an action, you can use an object as payload:

```js
const logIn = createAction('auth/logIn').withPayload()

login({ username: 'alice', password: 'ecila' })
// =>
// {
//   type: 'auth/logIn',
//   payload: { username: 'alice', password: 'ecila' }
// }
```

## Next Steps

Defining actions is one thing, but you also need the reducers to handle them. Redux Preboiled can help you with that too, as you'll see in the [Reducers guide](/guides/reducers).


# Reducers

Redux [reducers](https://redux.js.org/basics/reducers) are usually written using `switch` statements, with each case handling a specific action type.

```js
function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'increment':
      return state + 1
    case 'decrement':
      return state - 1
    case 'multiply':
      return state * action.payload
    default:
      return state
  }
}
```

This pattern works reasonably well, but also has drawbacks:

* There is some required boilerplate, specifically the wrapping `switch (action.type)` block and the `default: return state` case (the latter is easy to forget when writing a new reducer).
* You have to remember the idiosyncrasies of JavaScript's `switch` statements, such as the additional braces needed to define variables which should be local to a case (e.g., `case 'multiply': { const factor = action.payload; … }`).
* In TypeScript, ensuring that `action` is typed correctly in every `switch` branch requires a considerable amount of extra typing effort, often including [union types of all types of actions in the app](https://redux.js.org/recipes/usage-with-typescript#type-checking-actions-action-creators).

Redux Preboiled has several helpers for constructing reducers which address these shortcomings. Here is how you might write the example reducer above with Preboiled:

```js
import {
  chainReducers,
  onAction,
  withInitialState
} from 'redux-preboiled'

const counterReducer = chainReducers(
  withInitialState(0),
  onAction('increment', state => state + 1),
  onAction('decrement', state => state - 1),
  onAction('multiply', (state, action) => state * action.payload)
)
```

This guide details Preboiled's reducer helpers and how they relate, plus how they help you reduce typing effort if you use TypeScript.

## Reducing Specific Actions

Preboiled's [`onAction`](/api/onaction) helper generates reducer-like functions which update the state only in response to actions of a specific type.

```js
import { onAction } from 'redux-preboiled'

const onMultiply = onAction('multiply', (state, action) => {
  return state * action.payload
})

onMultiply(2, { type: 'multiply', payload: 4 })
// => 8

onMultiply(2, { type: 'increment' })
// => 2
```

Note that the functions returned by `onAction` are not "proper" reducers - they don't provide an initial state. For this reason, we prefer to call them **sub-reducers** as they are meant to be embedded into actual reducer functions. Later in this guide, we'll see how this can be done easily with the `withInitialState` and `chainReducers` helpers.

### Integration with `createAction`

If you generate your action creators using [`createAction`](/api/createaction) (as described in the [Actions guide](/guides/actions)), you can pass them directly to `onAction` in place of their corresponding action types.

```js
import { createAction, onAction } from 'redux-preboiled'

const multiply = createAction('multiply').withPayload()

const onMultiply = onAction(multiply, (state, action) => {
  return state + action.payload
})
```

This removes a bit of noise as you don't need to write `onAction(multiply.type, ...)`.

If you use TypeScript, there is another benefit: based on the action creator's type, the TypeScript compiler automatically infers the type of the `action` argument passed to the state update function. This helps you prevent mistakes, like in the following example:

```ts
// TypeScript

// If I forget to call .withPayload() here...
const multiply = createAction('multiply')

const onMultiply = onAction(multiply, (state, action) => {
  // ... the TypeScript compiler will complain here:
  // Property 'payload' does not exists on type 'Action<"multiply">'.
  return state * action.payload
})
```

You'll also get better autocompletion in IDE's and editors which understand TypeScript, such as Visual Studio Code or WebStorm.

## Providing Initial State

Using the `withInitialState` helper, you can generate reducers which return a specific value as initial state.

There are two ways to use this helper. The first is to pass an initial state value and a reducer-like state update function. The resulting reducer will forward all calls to that function unless called with an `undefined` state (i.e., during Redux store initialization), in which case it returns the given initial state value instead. One use case for this variant is to make a full reducer from a single `onAction` sub-reducer:

```js
import { onAction, withInitialState } from 'redux-preboiled'

const onIncrement = onAction('increment', state => state + 1)
const reducer = withInitialState(0, onIncrement)

reducer(undefined, { type: '@@INIT' })
// => 0

reducer(0, { type: 'increment' })
// => 1
```

Alternatively, you can specify *only* an initial state when calling `withInitialState`. In this case, the reducer will simply return any non-`undefined` state unchanged.

```js
const reducer = withInitialState(0)

reducer(undefined, { type: '@@INIT' })
// => 0

reducer(123, { type: '' })
// => 123
```

This second version of `withInitialState` is useful for *reducer chains*, which we'll look at next.

## Chaining Reducers

Redux comes with the [`combineReducers`](https://redux.js.org/api/combinereducers) function, which allows you to compose multiple reducers for different state slices. Preboiled complements this with [`chainReducers`](/api/chainreducers), which is about composing reducers for the *same* state slice.

`chainReducers` turns a sequence of (sub-)reducers into a pipeline, or "chain", where the output state of one reducer becomes the input state for the next. Let's look at a silly, but illustrative example:

```js
import { chainReducers } from 'redux-preboiled'

const uppercaseReducer = (state = '', action) => {
  return state + action.payload.toUppercase()
}

const lowercaseReducer = (state, action) => {
  return state + action.payload.toLowerCase()
}

const reducer = chainReducers(
  uppercaseReducer,
  lowercaseReducer
)

reducer('', { type: '', payload: 'a' })
// => 'Aa'

reducer('A', { type: '', payload: 'b' })
// => 'AaBb'
```

For every incoming action, the reducer above first forwards the call to `uppercaseReducer`, the first reducer in the chain. It then passes the resulting state to the second reducer (`lowercaseReducer`), whose return value finally becomes the state returned by the chained reducer itself.

Note that for the chain to be a proper reducer, at least one of its functions (usually the first one) must return an initial state if called with an `undefined` state. A common pattern is to start the chain with a `withInitialState` reducer, e.g.:

```js
const reducer = chainReducers(
  withInitialState(''),
  lowercaseReducer,
  uppercaseReducer
)
```

## Replacing `switch`

As shown in this guide's introduction, you can chain multiple `onAction` sub-reducers as a replacement for the `switch` reducer pattern.

```js
const counterReducer = chainReducers(
  withInitialState(0),
  onAction('increment', state => state + 1),
  onAction('multiply', (state, { payload }) => state * payload)
)
```

This works because each sub-reducer only reacts to one specific type of action, and leaves the state unchanged for all others; incoming actions will thus pass through the chain until they reach the matching sub-reducer, or leave the chain without a state change (the equivalent of `default: return state` in the `switch` pattern).

## Next Steps

In addition to defining actions and reducers, Redux Preboiled also helps you with testing your Redux code. See the [Testing guide](/guides/testing).


# Testing

Redux boilerplate does not only accumulate in production code, but also in unit tests. To help you reduce it, Preboiled offers two reducer test helpers - `getInitialState` and `reduceActions` - which are described in the following sections.

Note that in this guide we assume you use [Jest](https://jestjs.io/) as your testing framework. However, Preboiled doesn't depend on Jest in any way, and it should be easy to translate the examples to your testing framework of choice.

## Testing Initial State

When testing reducers, you'll usually want to check if the initial state looks as expected.

```js
import reducer from './module'

test('initial state is 0', () => {
  const initialState = reducer(undefined, { type: '' })
  expect(initialState).toBe(0)
})
```

[`getInitialState`](/api/getinitialstate) makes such tests a bit more readable. It simply returns the initial state of a reducer by calling it with an `undefined` state, just as in the snippet above.

```js
import { getInitialState } from 'redux-preboiled'
import reducer from './module'

test('initial state is 0', () => {
  expect(getInitialState(reducer)).toBe(0)
})
```

## Reducing Multiple Actions

It is often important to test a reducer's state after a sequence of multiple actions were dispatched, rather than just a single one. Loading flags for asynchronous actions are a common example: you'll want to ensure that the flag is set to `true` when the initiating action is dispatched, but also that it's set back to `false` if the corresponding success or failure action is dispatche afterwards.

```js
import { getInitialState } from 'redux-preboiled'
import reducer, { fetchStart, fetchDone } from './module'

let initialState

beforeAll(() => {
  initialState = getInitialState(reducer)
})

describe('on fetchStart', () => {
  test('loading flag is set', () => {
    const state = reducer(initialState, fetchStart())
    expect(state.isFetching).toBe(true)
  })
})

describe('on fetchDone', () => {
  test('loading flag is unset', () => {
    const state1 = reducer(initialState, fetchStart())
    const state2 = reducer(state1, fetchDone('data'))
    expect(state2.isFetching).toBe(false)
  })
})
```

To make tests like these easier to write, Redux Preboiled offers the [`reduceActions`](/api/reduceactions) helper. It takes a reducer and a sequence of actions, and returns the state after all actions have been processed. It also automatically gets the reducer's initial state and passes it together with the first action in the sequence.

```js
import {
  chainReducers,
  createAction,
  onAction,
  reduceActions,
  withInitialState
} from 'redux-preboiled'

const increment = createAction('increment')

const counterReducer = chainReducers(
  withInitialState(0),
  onAction(increment, state => state + 1)
)

reduceActions(counterReducer, increment())
// => 1

reduceActions(counterReducer, increment(), increment())
// => 2
```

Using this helper, we can condense the tests above to:

```js
import { reduceActions } from 'redux-preboiled'
import reducer, { fetchStart, fetchDone } from './module'

describe('on fetchStart', () => {
  test('loading flag is set', () => {
    const state = reduceActions(reducer, fetchStart())
    expect(state.isFetching).toBe(true)
  })
})

describe('on fetchDone', () => {
  test('loading flag is unset', () => {
    const state = reduceActions(reducer, fetchStart(), fetchDone('data'))
    expect(state.isFetching).toBe(false)
  })
})
```

If you want to start the reduction from a specific starting state, you can use the [`reduceActionsFrom`](https://github.com/denisw/redux-preboiled/blob/master/docs/api/reduceActionsFrom.md) helper instead.

```js
reduceActionsFrom(0, counterReducer, increment())
// => 1

reduceActionsFrom(3, counterReducer, increment(), increment())
// => 5
```

## Next Steps

The current set of testing helpers is still very small. If there are any other helpers you'd like to see, feel free to [file an issue](https://github.com/denisw/redux-preboiled/issues/new).

This guide concludes our tour through Redux Preboiled. For more examples, looking at the repository's [examples](https://github.com/denisw/redux-preboiled/tree/master/examples) directory. Reference documentation on all helpers can be found in the [API section](/api/api).


# API Overview

Below you'll find links to the API documentation pages of all Redux Preboiled helpers, grouped by topic.

### Actions

* [`createAction`](/api/createaction)

### Reducers

* [`chainReducers`](/api/chainreducers)
* [`onAction`](/api/onaction)
* [`withInitialState`](/api/withinitialstate)

### Testing

* [`getInitialState`](/api/getinitialstate)
* [`reduceActions`](/api/reduceactions)


# chainReducers

Creates a reducer that chains together a sequence of (sub-)reducers.

```js
// JavaScript

function chainReducers(firstChildReducer, ...otherChildReducers)
```

```ts
// TypeScript

function chainReducers<S = any, A extends Action = AnyAction>(
  firstChildReducer: Reducer<S, A>,
  ...otherChildReducers: SubReducer<S, A>[]
): Reducer<S, A>
```

## Details

Given a sequence of (sub-)reducers, `chainReducers` creates a reducer which forwards incoming actions to each of these "child" reducers. More specifically, the reducer:

1. calls the first child reducer with the received state
2. passes the resulting state (and the same action) to the next reducer
3. repeats step 2 until reaching the last reducer, whose returned state is finally returned by the `chainReducers` reducer.

Note that the first child reducer in the chain is the only one which needs to handle an `undefined` state by returning the initial state; all others can be *sub-reducers* - such as the ones returned by [`onAction`](/api/onaction) - which assume that they are only ever called with a defined, already-initialized state.

## Examples

Chaining `withInitialState` and `onAction` reducers:

```js
import {
  chainReducers,
  onAction,
  withInitialState
} from 'redux-preboiled'

const reducer = chainReducers(
  withInitialState(0),
  onAction('increment', state => state + 1),
  onAction('multiply', (state, { payload }) => state * payload)
)

reducer(undefined, { type: '' })
// => 0

reducer(0, { type: 'increment' })
// => 1

reducer(2, { type: 'multiply', payload: 4 })
// => 8
```

## See Also

* [Reducers](/guides/reducers) guide
* [onAction](/api/onaction)
* [withInitialState](/api/withinitialstate)


# createAction

Generates an action creator for a specific action type.

```js
// JavaScript

function createAction(type)
```

```ts
// TypeScript

function createAction<T extends string | symbol | number>(
  type: T
): BasicActionCreator<T>
```

## Details

`createAction` takes an action type value and returns an [action creator](https://redux.js.org/basics/actions#action-creators) which produces actions of that type.

For a version of the action creator which accepts a `payload` value and attaches the returned action, call the `withPayload()` method (e.g., `createAction("…").withPayload()`.)

In addition to `withPayload()`, action creators returned by `createAction()` have the following properties:

* **`type`:** The type value passed to `createAction()`. Removes the need for a separate action type constant, and allows other helpers such as [`onAction`](/api/onaction) to inspect the `type` value of the produced actions at runtime.
* **`matches(action)`:** A method that returns true the the passed action has the same `type` as the ones produced by the action creator.

### TypeScript Notes

* `.withPayload()` is defined with a type parameter that specifies the payload type. You can override the default (`any`) by specifying the type parameter explicitly:

  ```ts
  const incrementBy = createAction('incrementBy').withPayload<number>();
  ```
* `.matches()` is defined as a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). Using it in a condition allows the TypeScript compiler to narrow the type of passed action to the specific type of action returned by the action creator:

  ```ts
  if (incrementBy.matches(action)) {
    const amount = action.payload
    // Type is inferred to be `number` due to matches()
  }
  ```

## Examples

Defining a basic action:

```js
import { createAction } from 'redux-preboiled'

const increment = createAction('increment')

increment()
// => { type: 'increment' }

increment.type
// => 'increment'
```

Defining an action with payload:

```js
import { createAction } from 'redux-preboiled'

const multiply = createAction('multiply').withPayload()

multiply(2)
// => { type: 'multiply', payload: 2 }

multiply.type
// => 'multiply'

multiply.matches({ type: 'multiply', payload: 1 })
// => true

multiply.matches({ type: 'increment' })
// => false
```

Specifying the action payload type (TypeScript):

```ts
import { createAction } from 'redux-preboiled'

const multiply = createAction('multiply').withPayload<number>()

multiply(2)
// OK

multiply('2')
// ERROR: Argument of type '2' is not assignable to parameter of
// type 'number'.
```

## See Also

* [Actions](/guides/actions) guide
* [onAction](/api/onaction)


# getInitialState

Returns the initial state of a reducer.

```js
// JavaScript

function getInitialState(reducer)
```

```ts
// TypeScript

function getInitialState<S>(reducer: Reducer<S>): S
```

## Details

`getInitialState` asks the passed reducer for its initial state by calling it with an `undefined` state and a dummy action, just as a Redux store would.

This helper is mainly intended for tests, where it can help improve readabilty. For example, when making assertions about a reducer's initial state, `getInitialState(reducer)` is more expressive than something like `reducer(undefined, { type: '' })`.

## Examples

Basic usage:

```js
import { getInitialState } from 'redux-preboiled'

const reducer = (state = 0, action) =>
  action.type === 'increment' ? state + 1 : state


getInitialState(reducer)
// => 0
```

Usage in [Jest](https://jestjs.io/):

```js
import { getInitialState } from 'redux-preboiled'

const reducer = (state = 0, action) =>
  action.type === 'increment' ? state + 1 : state

test('initial state is 0', () => {
  expect(getInitialState(reducer)).toBe(0);
})
```

## See Also

* [Testing](/guides/testing) guide


# onAction

Creates a sub-reducer for a particular action type.

```js
// JavaScript

function onAction(type, getNextState?)
```

```ts
// TypeScript

function onAction<
  S = any,
  T extends string | symbol | number = any,
  A extends Action<T> = AnyAction
>(
  type: T,
  actionReducer: SubReducer<S, A>
): SubReducer<S>

function onAction<
  S = any,
  A extends Action = AnyAction
>(
  actionCreator: TypedActionCreator<A>,
  actionReducer: SubReducer<S, A>
): SubReducer<S>
```

## Details

`createAction` returns a sub-reducer that checks each incoming action's type against the one specified and, on a match, delegates to the passed reducer-like `getNextState` function. For non-matching actions, the sub-reducer simply returns the unchanged input state.

The action type to match against can be specifed in two ways. The simplest way is to pass the action type value. Alternatively, you can pass an action creator generated by [`createAction`](/api/createaction); in this case, the action creator's `type` property is used to determine the action type.

Note that the function returned by onAction is a *sub-reducer* - rather than proper Redux reducer - because it does not provide an initial state. Instead, it expects to be embedded into a full reducer which takes care of state initialization. Such a reducer can be generated using [`withInitialState`](/api/withinitialstate) and its `subReducer` parameter, or by combining `withInitialState` and [`chainReducers`](/api/chainreducers).

### TypeScript Notes

If you specify the action type using a `createAction` action creator, the type of the `getNextState` function's `action` parameter will be automatically inferred from the type of the action creator.

```ts
import { createAction, onAction } from 'redux-preboiled'

const multiply = createAction('multiply').withPayload<number>()
// multiply: PayloadActionCreator<number>

const multiplySubReducer = onAction('multiply', (state, action) => {
  // action: PayloadAction<number, 'multiply'>
  return state * action.payload
})
```

## Examples

Basic usage:

```js
import { onAction } from 'redux-preboiled'

const subReducer = onAction(
  'multiply',
  (state, action) => state * action.payload
)

subReducer(2, { type: 'multiply', payload: 4 })
// => 8

subReducer(2, { type: 'increment' })
// => 2
```

Specifying the action type with a `createAction` action creator:

```js
import { createAction, onAction } from 'redux-preboiled'

const increment = createAction('increment')
const multiply = createAction('multiply').withPayload()

const subReducer = onAction(
  multiply,
  (state, action) => state * action.payload
)

subReducer(2, multiply(4))
// => 8

subReducer(2, increment())
// => 2
```

## See Also

* [Reducers](/guides/reducers) guide
* [`createAction`](/api/createaction)


# reduceActions

*Testing helper.* Calculates the state after dispatching an sequence of actions to a specific reducer, starting from the initial state.

```js
// JavaScript

function reduceActions(reducer, ...actions)
```

```ts
// TypeScript

function reduceActions<S, A extends Action, AS extends A[]>(
  reducer: Reducer<S, A>,
  ...actions: AS
): S
```

## Details

`reduceActions` calls `reducer` with each of the passed `actions` - as if these had been dispatched in the specified order - and returns the resulting state. For the first reducer call, the reducer's initial state (as determined by [`getInitialState`](/api/getinitialstate)) is used; each following call receives the state returned by the previous one.

If called without any actions, `reduceActions` simply returns the reducer's initial state - that is, `reduceActions(reducer)` is equivalent to `getInitialState(reducer)`.

This helper is meant for use in reducer tests.

## Examples

Basic usage:

```js
import { reduceActions } from 'redux-preboiled'

const reducer = (state = 0, action) => {
  switch (action.type) {
    case 'increment':
      return state + 1
    case 'multiply':
      return state * action.payload
    default:
      return state
  }
}

reduceActions(reducer, { type: 'increment' })
// => 1

reduceActions(
  reducer,
  { type: 'increment' },
  { type: 'increment' },
  { type: 'multiply', payload: 2 }
)
// => 4

reduceActions(reducer)
// => 0
```

Usage in a [Jest](https://jestjs.io/) test:

```js
import { reduceActions } from 'redux-preboiled'
import counterReducer, {
  increment,
  multiply
} from './counter.redux'

test('increment', () => {
  const state = reduceActions(counterReducer, increment())
  expect(state).toEqual(1)
})

test('increment and multiply', () => {
  const state = reduceActions(
    counterReducer,
    increment(),
    increment(),
    multiply(4)
  )
  expect(state).toEqual(8)
})
```

## See Also

* [Testing](/guides/testing) guide


# withInitialState

Creates a reducer that provides an initial state value, optionally wrapping a sub-reducer.

```js
// JavaScript

function withInitialState(state, subReducer?)
```

```ts
// TypeScript

function withInitialState<S, A extends Action>(
  initialState: S,
  reducer?: InitializedReducer<S, A>
): Reducer<S, A>
```

## Details

Given a value, `withInitialState` creates a reducer which provides that value as the initial state - that is, the reducer returns the value if called with the state `undefined`.

If a `subReducer` is passed, the reducer will delegate to it once the state has been initialized. Used this way, `withInitialState` basically converts a sub-reducer that doesn't provide an initial state into a proper reducer that does.

Without `subReducer`, the reducer will simply return any non-`undefined` state it receives. This means it will not make any state changes after the initial state has been provided. This form of `withInitialState` is meant to be used as building block for reducer chains built with [`chainReducers`](/api/chainreducers).

## Examples

Using `withInitialState` without sub-reducer:

```js
import { withInitialState } from 'redux-preboiled'

const reducer = withInitialState(0)

reducer(undefined, { type: '' })
// => 0

reducer(123, { type: '' })
// => 123
```

Passing a sub-reducer:

```js
import { withInitialState } from 'redux-preboiled'

function counterReducer(state, action) {
  return action.type === 'increment' ? state + 1 : state
}

const reducer = withInitialState(0, counterReducer)

reducer(undefined, { type: '' })
// => 0

reducer(0, { type: 'increment' })
// => 1
```

Combining `withInitialState` with `chainReducers`:

```js
import { chainReducers, withInitialState } from 'redux-preboiled'

function incrementReducer(state, action) {
  return action.type === 'increment' ? state + 1 : state
}

function multiplyReducer(state, action) {
  return action.type === 'multiply' ? state * action.payload : state
}

const reducer = chainReducers(
  withInitialState(0),
  incrementReducer,
  multiplyReducer
)

reducer(undefined, { type: '' })
// => 0

reducer(0, { type: 'increment' })
// => 1

reducer(2, { type: 'multiply', payload: 4 })
// => 8
```

## See Also

* [`chainReducers`](/api/chainreducers)


# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/denisw/redux-preboiled/compare/v0.4.1...HEAD)

(Nothing yet.)

## [0.5.1](https://github.com/denisw/redux-preboiled/compare/v0.5.0...v0.5.1)

### Fixed

* Don't throw a `TypeError` if the `matches()` method of an action creator is called independently from the action creator object. Allows idioms such as `filter(actionCreator.matches)` without having to resort to `Function.prototype.bind` (`actionCreator.matches.bind(actionCreator)`).

## [0.5.0](https://github.com/denisw/redux-preboiled/compare/v0.4.1...v0.5.0)

### Added

* `createAction` action creators now have a `matches()` method, which returns true if the passed action's `type` matches that of the creator. In TypeScript, `matches()` is defined as a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates).

### Changed

* **TypeScript:** The `SimpleActionCreator` type is now called `BasicActionCreator`. `SimpleActionCreator` is kept as a type alias, but is deprecated.

## [0.4.1](https://github.com/denisw/redux-preboiled/compare/v0.4.0...v0.4.1)

### Fixed

* `onAction`: Accept symbols and numbers as action types (\[@judithhartman]\[<https://github.com/judithhartmann>])

## [0.4.0](https://github.com/denisw/redux-preboiled/compare/v0.3.1...v0.4.0)

### Fixed

* **TypeScript:** Fix a type error with TypeScript v3.6 when passing actions of different types to `reduceActions` and `reduceActionsFrom`.
* Documentation fixes by [@k-nut](https://github.com/k-nut) and [@dannyfritz](https://github.com/dannyfritz).

### Internal

* Redux Preboiled now has a suite of TypeScript type definition tests powered by [tsd](https://github.com/SamVerschueren/tsd). This should help ensure that the typings don't break on new TypeScript releases.
* Upgrade TypeScript to v3.6.4.
* Upgrade Rollup to v1.23.1.
* Upgrade Babel to v7.6.4.

## [0.3.1](https://github.com/denisw/redux-preboiled/compare/v0.3.0...v0.3.1) - 2019-05-02

### Fixed

* Ship typings (they were accidentally ommitted from v0.3.0).

## [0.3.0](https://github.com/denisw/redux-preboiled/compare/v0.2.0...v0.3.0) - 2019-05-02

### Changed

* The "main" build is now a UMD module which can be used both in Node.js and directly the browser. In the latter case, Redux Preboiled is exposed as a global named `reduxPreboiled`.
* All builds (except the `esnext` one) are now transpiled to ES5, which makes them work in older browsers (most notably Internet Explorer 11).

## [0.2.0](https://github.com/denisw/redux-preboiled/compare/v0.1.0...v0.2.0) - 2019-04-24

### Added

* New helper: [`reduceActionsFrom`](https://redux-preboiled.js.org/api/reduceactionsfrom). Like [`reduceActions`](https://redux-preboiled.js.org/api/reduceactions), but starting with a custom state (instead of the reducer's initial state).

### Changed

* Improve testing guide.
* Add a license link to `README.md`.


# License

The MIT License (MIT)

Copyright (c) 2019-present Denis Washington

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


