redux-detector
Version:
Redux enhancer for pure detection of state changes.
161 lines (113 loc) β’ 5.65 kB
Markdown
<div align="center">
<h1>Redux Detector</h1>
<p>Redux enhancer for pure detection of state changes π</p>
[](https://www.npmjs.com/package/redux-detector)
[](https://travis-ci.org/piotr-oles/redux-detector)
[](https://coveralls.io/github/piotr-oles/redux-detector?branch=master)
[](https://github.com/facebook/jest)
[](https://github.com/prettier/prettier)
[](http://commitizen.github.io/cz-cli/)
</div>
## Table of Contents π
- [Installation π¦](#installation)
- [Concept π‘](#concept)
- [Basics π](#basics)
- [API reference π](doc/api.md)
- [Code splitting βοΈ](#code-splittingοΈ)
- [Typings π](#typings)
- [License](#license)
## Installation π¦
Redux Detector requires **Redux 3.1.0 or later.**
```sh
npm install --save redux-detector
```
This assumes that youβre using [npm](http://npmjs.com/) package manager with a module bundler like
[Webpack](https://webpack.js.org/) to consume [ES6](https://webpack.js.org/api/module-methods/#es6-recommended) or
[CommonJS](https://webpack.js.org/api/module-methods/#commonjs) modules.
To enable Redux Detector, use `createDetectorEnhancer`:
```js
import { createStore } from "redux";
import { createDetectorEnhancer } from "redux-detector";
import { rootReducer } from "./store/reducer/rootReducer";
import { rootDetector } from "./store/detector/rootDetector";
const store = createStore(rootReducer, createDetectorEnhancer(rootDetector));
```
## Concept π‘
Redux Detector [enhancer](http://redux.js.org/docs/api/createStore.html) allows you to **detect state changes** in the Redux.
The **`Detector`** is a pure function which accepts previous and next state and returns something for given states transition.
```typescript
type Detector<TState, TResult> = (
prevState: TState | undefined,
nextState: TState | undefined
) => TResult;
```
The **`Actions Detector`** is a `Detector` which returns action, list of actions or nothing.
Returned actions are automatically dispatched by the enhancer.
```typescript
import { Detector } from "redux-detector";
import { Action } from "redux";
type ActionsDetector<TState, TAction extends Action> = Detector<
TState,
TAction | TAction[] | void
>;
```
Another type of the detector is the **`Condition Detector`** which returns boolean values.
```typescript
import { Detector } from "redux-detector";
type ConditionDetector<TState> = Detector<TState, boolean>;
```
These two types of detectors have different responsibility:
- `Condition Detectors` describes a condition that we want to detect
- `Actions Detectors` describes which action we want to dispatch
Thanks to its functional nature and purity, detectors are easy to test. They don't break [Single Source of Truth principle](https://en.wikipedia.org/wiki/Single_source_of_truth)
as the input is only previous and next state.
## Basics π
Let's start simply - implement a condition detector that checks if number of login attempts exceeded 3.
```typescript
export const exceededLoginAttemptsLimit = (prevState, nextState) =>
prevState.attempts <= 3 && nextState.attempts > 3;
```
We can make above example more generic - `prevState.attempts <= 3` is the same as `!(prevState.attempts > 3)`.
That means that we check if some condition is **not truthy** for the _previous state_ but is **truthy** for the _next state_.
This kind of transition can be handled by the `changedToTruthy` function.
```typescript
import { changedToTruthy } from "redux-detector";
export const exceededLoginAttemptsLimit = changedToTruthy(
state => state.attempts > 3
);
```
> Redux Detector library provides other useful functions to model condition detectors - please check the
> [API documentation](doc/api.md) to learn more.
The next step is to use an action detector to dispatch an action when the limit became exceeded.
To do so, we will use `composeIf` function.
```typescript
import { composeIf, changedToTruthy } from "redux-detector";
import { blockUser } from "../action/userAction";
const blockUserDetector = composeIf(
changedToTruthy(state => state.attempts > 3),
() => blockUser()
);
```
The `createDetectorEnhancer` function accepts only one detector, so we have to compose all
detectors to the one `rootDetector`.
```typescript
import { composeDetectors } from "redux-detector";
import { blockUserDetector } from "./userDetector";
// other detectors...
import { companyDetector } from "./companyDetector";
export const rootDetector = composeDetectors(
blockUserDetector,
companyDetector
);
```
And that's all - `redux-detector` will dispatch `blockUser()` when login attempts exceeded 3 π
## [API reference π](doc/api.md)
For more detailed documentation, please check API reference.
## Code splitting βοΈ
Redux Detector provides `replaceDetector` method on `DetectableStore` interface (store created by Redux Detector). It's similar to
`replaceReducer` - it changes detector and dispatches `{ type: '@@detector/INIT' }`.
## Typings π
If you are using [TypeScript](https://www.typescriptlang.org/), typings are provided in the npm package.
This library doesn't provide [Flow](https://flow.org/) typings.
## License
MIT