I create a package to simplify the work when using useReducer
Tags: react, javascript, package, opensource
Published: 2022-05-01 17:14:29

Using `useReducer` to handle complicated state is preferable than using `useState`. However, writing a reducer is kind of annoying because we may need to write so many `switch/case` to determine which action we are going to handle. Furthermore, we may prefer writing action creators to generate actions instead of writing an action directly.

To solve these problems, I write a package called [use-case-reducers](https://www.npmjs.com/package/use-case-reducers) to simplify our work.

## Features of this package

1. [Use an object to generate a reducer](#use-an-object-to-generate-a-reducer)
2. [Automatically generate action creators](#automatically-generate-action-creators)
3. [Allow mutating state in case reducer](#allow-mutating-state-in-case-reducer)

### Use an object to generate a reducer

Instead of writing a reducer function, **use-case-reducers** use an object containing case reducers to generate a reducer. A case reducer is a function that only handles one case of actions. For example, if we want to handle a counter state with two actions `increment` and `add`, then the object may look like:

```js
const caseReducers = {
  increment: state => ({count: state + 1}),
  add: (state, amount) => ({count: state + amount}),
}
```

### Automatically generate action creators

**use-case-reducers** will generate all action creators corresponding to the case reducers you pass in. Take the above `caseReducers` for example, it will generate two action creators `increment()` and `add(amount)`.

### Allow mutating state in case reducer

This package use [immer](https://immerjs.github.io/immer/) in the generated reducer, so we can mutate the state inside our case reducers. We can rewrite the above `caseReducers` to:

```js
const caseReducers = {
  increment: state => {state.count += 1},
  add: (state, amount) => {state.count += amount},
}
```

This feature may be useful when our state is very complicated.

## How to use this package

Use `npm` or `yarn` to install it as a dependency:

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

We are going to write a component with a counter state and use this package to update it.

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

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

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

  return (
    <div>
      count: {state.count}
      <button onClick={() => dispatch(increment())}>increment</button>
      <button onClick={() => dispatch(add(10))}>add 10</button>
    </div>
  )
}
```

Let's look the same component but writing with `useReducer`.

```js
import {useReducer} from 'react'

const initialState = {count: 0};
const reducer = (state, action) => {
  switch(action.type) {
    'increment': {
      return {count: state.count + 1};
    }
    'add': {
      return {count: state.count + action.payload};
    }
  }
}

const increment = () => ({type: 'increment'});
const add = (amount) => ({type: 'add', payload: amount});

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

  return (
    <div>
      count: {state.count}
      <button onClick={() => dispatch(increment())}>increment</button>
      <button onClick={() => dispatch(add(10))}>add 10</button>
    </div>
  )
}
```

As you can see, we can write less code with `use-case-reducers`. Hope this package will help you. Have a good day!