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.
- Host: GitHub
- URL: https://github.com/jason89521/use-case-reducers
- Owner: jason89521
- Created: 2022-04-26T09:52:40.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2022-05-02T10:33:45.000Z (about 4 years ago)
- Last Synced: 2025-03-03T17:05:40.958Z (over 1 year ago)
- Topics: react, usereducer-hook
- Language: TypeScript
- Homepage:
- Size: 325 KB
- Stars: 2
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 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.