An open API service indexing awesome lists of open source software.

https://github.com/jason89521/use-case-reducers

A simplified version of React's useReducer, use this package to generate all actions automatically.
https://github.com/jason89521/use-case-reducers

react usereducer-hook

Last synced: 2 months ago
JSON representation

A simplified version of React's useReducer, use this package to generate all actions automatically.

Awesome Lists containing this project

README

          

# Use Case Reducers

[![npm](https://img.shields.io/npm/v/use-case-reducers)](https://www.npmjs.com/package/use-case-reducers)

`useCaseReducers` simplifies the work when you are using React's `useReducer`. Its api is almost the same as `useReducer`, so there are just a few things that you need to learn if you have already been familiar with `useReducer`.

- [Get started](#get-started)
- [Why use this package](#why-use-this-package)
- [What is a case reducer](#what-is-a-case-reducer)
- [API Reference](#api-reference)
- [useCaseReducers](#usecasereducers)
- [Lazy initialization](#lazy-initialization)
- [The parameters for a case reducer](#the-parameters-for-a-case-reducer)
- [createCaseReducers](#createcasereducers)
- [createSlice](#createslice)
- [createActions](#createactions)
- [createReducer](#createreducer)

## Get started

```bash
npm install use-case-reducers
#or
yarn add use-case-reducers
```

## Why use this package

Although `useReducer` is great, writing a reducer is kind of annoying, especially when we need to handle more actions. Suppose we need to handle 10 actions with our state, then we need to write 10 `switch/case` of 10 `if/else` to deal with these actions. Sounds terrible, right?

Furthermore, when we use `useReducer`, we probably don't want to dispatch an action by writing `dispatch({type: 'addTodo', payload: newTodo})`. The common use case we prefer may be writing an action creator for each action. For example, we may write:

```js
// An action creator returns the action of adding a to-do
const addTodo = newTodo => ({ type: 'addTodo', payload: newTodo });
// Dispatch a action of adding a to-do by passing a action creator
dispatch(addTodo(newTodo));
```

Action creators help us writing cleaner code. But again, what if we need to handle so many actions? We definitely don't want to write these action creators manually, right?

`useCaseReducers` comes to the rescue! With `useCaseReducers`, we don't need to write a lot of `switch/case` and a lot of action creators. All we need to do is passing an object of case reducers, then `useCaseReducers` will generate a reducer and all action creators automatically.

## What is a case reducer

The difference between a case reducer and a normal reducer is that a case reducer only handles one action while a normal reducer handles all actions. For example, if we use a reducer to handle a counter state, we may write:

```js
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
case 'add':
return state + action.payload;
case 'sub':
return state - action.payload;
}
};
```

We can split the above reducer into 4 case reducers:

```js
const increment = state => state + 1;
const decrement = state => state - 1;
const add = (state, amount) => state + amount;
const sub = (state, amount) => state - amount;
```

As you can see, writing a case reducer is very easy.

## API Reference

This package uses [Immer](https://github.com/immerjs/immer), so you can mutate the state in your case reducers.

### useCaseReducers

```js
import useCaseReducers from 'use-case-reducers';

const [state, dispatch, actions] = useCaseReducers(caseReducers, initialArg, init);
```

The differences between `useCaseReducers` and `useReducer` are the first parameter and there is a third returned value in `useCaseReducers`. Instead of passing a normal reducer to the first parameter, `useCaseReducers` accepts an object which contains all case reducers. The third returned value is an object which contains all action creators generated by the `caseReducers` you pass in. Here is an example of how to use it:

```jsx
const initialState = { count: 0 };
const caseReducers = {
increment: state => {
state.count += 1;
},
decrement: state => {
state.count -= 1;
},
add: (state, amount) => {
state.count += amount;
},
sub: (state, amount) => {
state.count -= amount;
},
};

const Counter = () => {
const [{ count }, dispatch, { increment, decrement, add, sub }] = useCaseReducers(
caseReducers,
initialState
);

return (


count: {count}
dispatch(increment())}>+
dispatch(decrement())}>-
dispatch(add(10))}>add 10
dispatch(sub(10))}>minus 10

);
};
```

#### Lazy initialization

Like `useReducer`, you can also create the initial state lazily by providing an `init` function as the third parameter. The initial state will be set to `init(initialArg)`.

#### The parameters for a case reducer

A case reducer can accepts an arbitrary number of parameters. Note that if a case reducer accepts more than one parameter, the first parameter is the state, and the rest parameters are the payload of a action. Here is an example:

```js
const caseReducers = {
// zero parameter
reset: () => {
return { count: 0 };
},
// one parameter, that is, it only accepts state
increment: state => {
state.count += 1;
},
// two parameters, the second is the payload
add: (state, amount) => {
state.count += amount;
},
// the number of the payload parameters is not constrained,
// that is, you can specify an arbitrary number of parameters to be the payload
addTwo: (state, amount1, amount2) => {
state.count += amount1 + amount2;
},
};
```

### createCaseReducers

```ts
import { createCaseReducers } from 'use-case-reducers';

const { initialState, caseReducers } = createCaseReducers(_initialState, _caseReducers);
```

If you are a typescript user, write a plain object of case reducers may be verbose. For example, if we want to write an object of case reducers to handle a state whose type is `number`, we should write something like the following code:

```ts
const caseReducers = {
increment: (state: number) => state + 1,
decrement: (state: number) => state - 1,
add: (state: number, amount: number) => state + amount,
sub: (state: number, amount: number) => state - amount,
};
```

As you can see, although the type of the `state` is the same, we need to specify its type for every case reducer.

An alternative solution is to use `createCaseReducers`. It can generate a well type defined object without specifing the type of `state` for every case reducer. Here is an example of how to use `createCaseReducers`:

```ts
const { initialState, caseReducers } = createCaseReducers(0, {
increment: state => state + 1,
decrement: state => state - 1,
add: (state, amount: number) => state + amount,
sub: (state, amount: number) => state - amount,
});
```

Note that this function just simply returns the `_initialState` and `_caseReducers` you pass in. It can be helpful when you are using typescript.

### createSlice

```js
import { createSlice } from 'use-case-reducers';

const { initialState, reducer, actions } = createSlice(_initialState, caseReducers);
```

If you want to use React's `useReducer` directly, then this function may be helpful for you. It will generate a reducer and all actions creators you need. Here is an example of how to use:

```jsx
const {
initialState,
reducer,
actions: { increment, decrement },
} = createSlice(0, {
increment: state => state + 1,
decrement: state => state - 1,
});

const App = () => {
const [state, dispatch] = useReducer(reducer, initialState);

return (


{state}

dispatch(increment())}>+
dispatch(decrement())}>-

);
};
```

### createActions

```ts
import { createActions } from 'use-case-reducers';

const actions = createActions(caseReducers);
```

If you only want to use action creators from your `caseReducers`, you can pass it to this function, then this function will return an object contains all action creators.

### createReducer

```ts
import { createReducer } from 'use-case-reducers';

const reducer = createReducer(caseReducers);
```

This function will return a reducer function generated by the `caseReducers` you pass in.