{"id":22269076,"url":"https://github.com/jason89521/use-case-reducers","last_synced_at":"2026-04-28T20:35:22.197Z","repository":{"id":57676198,"uuid":"485726514","full_name":"jason89521/use-case-reducers","owner":"jason89521","description":"A simplified version of React's useReducer, use this package to generate all actions automatically.","archived":false,"fork":false,"pushed_at":"2022-05-02T10:33:45.000Z","size":333,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-03T17:05:40.958Z","etag":null,"topics":["react","usereducer-hook"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jason89521.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-04-26T09:52:40.000Z","updated_at":"2023-03-07T04:36:24.000Z","dependencies_parsed_at":"2022-09-03T00:12:23.148Z","dependency_job_id":null,"html_url":"https://github.com/jason89521/use-case-reducers","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":"jason89521/vite-react-lib-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jason89521%2Fuse-case-reducers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jason89521%2Fuse-case-reducers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jason89521%2Fuse-case-reducers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jason89521%2Fuse-case-reducers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jason89521","download_url":"https://codeload.github.com/jason89521/use-case-reducers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245486365,"owners_count":20623244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","usereducer-hook"],"created_at":"2024-12-03T11:15:02.294Z","updated_at":"2026-04-28T20:35:22.168Z","avatar_url":"https://github.com/jason89521.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Use Case Reducers\n\n[![npm](https://img.shields.io/npm/v/use-case-reducers)](https://www.npmjs.com/package/use-case-reducers)\n\n`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`.\n\n\u003c!-- TOC --\u003e\n\n- [Get started](#get-started)\n- [Why use this package](#why-use-this-package)\n- [What is a case reducer](#what-is-a-case-reducer)\n- [API Reference](#api-reference)\n  - [useCaseReducers](#usecasereducers)\n    - [Lazy initialization](#lazy-initialization)\n    - [The parameters for a case reducer](#the-parameters-for-a-case-reducer)\n  - [createCaseReducers](#createcasereducers)\n  - [createSlice](#createslice)\n  - [createActions](#createactions)\n  - [createReducer](#createreducer)\n\n\u003c!-- /TOC --\u003e\n\n## Get started\n\n```bash\nnpm install use-case-reducers\n#or\nyarn add use-case-reducers\n```\n\n## Why use this package\n\nAlthough `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?\n\nFurthermore, 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:\n\n```js\n// An action creator returns the action of adding a to-do\nconst addTodo = newTodo =\u003e ({ type: 'addTodo', payload: newTodo });\n// Dispatch a action of adding a to-do by passing a action creator\ndispatch(addTodo(newTodo));\n```\n\nAction 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?\n\n`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.\n\n## What is a case reducer\n\nThe 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:\n\n```js\nconst reducer = (state, action) =\u003e {\n  switch (action.type) {\n    case 'increment':\n      return state + 1;\n    case 'decrement':\n      return state - 1;\n    case 'add':\n      return state + action.payload;\n    case 'sub':\n      return state - action.payload;\n  }\n};\n```\n\nWe can split the above reducer into 4 case reducers:\n\n```js\nconst increment = state =\u003e state + 1;\nconst decrement = state =\u003e state - 1;\nconst add = (state, amount) =\u003e state + amount;\nconst sub = (state, amount) =\u003e state - amount;\n```\n\nAs you can see, writing a case reducer is very easy.\n\n## API Reference\n\nThis package uses [Immer](https://github.com/immerjs/immer), so you can mutate the state in your case reducers.\n\n### useCaseReducers\n\n```js\nimport useCaseReducers from 'use-case-reducers';\n\nconst [state, dispatch, actions] = useCaseReducers(caseReducers, initialArg, init);\n```\n\nThe 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:\n\n```jsx\nconst initialState = { count: 0 };\nconst caseReducers = {\n  increment: state =\u003e {\n    state.count += 1;\n  },\n  decrement: state =\u003e {\n    state.count -= 1;\n  },\n  add: (state, amount) =\u003e {\n    state.count += amount;\n  },\n  sub: (state, amount) =\u003e {\n    state.count -= amount;\n  },\n};\n\nconst Counter = () =\u003e {\n  const [{ count }, dispatch, { increment, decrement, add, sub }] = useCaseReducers(\n    caseReducers,\n    initialState\n  );\n\n  return (\n    \u003cdiv\u003e\n      count: {count}\n      \u003cbutton onClick={() =\u003e dispatch(increment())}\u003e+\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e dispatch(decrement())}\u003e-\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e dispatch(add(10))}\u003eadd 10\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e dispatch(sub(10))}\u003eminus 10\u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n#### Lazy initialization\n\nLike `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)`.\n\n#### The parameters for a case reducer\n\nA 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:\n\n```js\nconst caseReducers = {\n  // zero parameter\n  reset: () =\u003e {\n    return { count: 0 };\n  },\n  // one parameter, that is, it only accepts state\n  increment: state =\u003e {\n    state.count += 1;\n  },\n  // two parameters, the second is the payload\n  add: (state, amount) =\u003e {\n    state.count += amount;\n  },\n  // the number of the payload parameters is not constrained,\n  // that is, you can specify an arbitrary number of parameters to be the payload\n  addTwo: (state, amount1, amount2) =\u003e {\n    state.count += amount1 + amount2;\n  },\n};\n```\n\n### createCaseReducers\n\n```ts\nimport { createCaseReducers } from 'use-case-reducers';\n\nconst { initialState, caseReducers } = createCaseReducers(_initialState, _caseReducers);\n```\n\nIf 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:\n\n```ts\nconst caseReducers = {\n  increment: (state: number) =\u003e state + 1,\n  decrement: (state: number) =\u003e state - 1,\n  add: (state: number, amount: number) =\u003e state + amount,\n  sub: (state: number, amount: number) =\u003e state - amount,\n};\n```\n\nAs you can see, although the type of the `state` is the same, we need to specify its type for every case reducer.\n\nAn 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`:\n\n```ts\nconst { initialState, caseReducers } = createCaseReducers(0, {\n  increment: state =\u003e state + 1,\n  decrement: state =\u003e state - 1,\n  add: (state, amount: number) =\u003e state + amount,\n  sub: (state, amount: number) =\u003e state - amount,\n});\n```\n\nNote that this function just simply returns the `_initialState` and `_caseReducers` you pass in. It can be helpful when you are using typescript.\n\n### createSlice\n\n```js\nimport { createSlice } from 'use-case-reducers';\n\nconst { initialState, reducer, actions } = createSlice(_initialState, caseReducers);\n```\n\nIf 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:\n\n```jsx\nconst {\n  initialState,\n  reducer,\n  actions: { increment, decrement },\n} = createSlice(0, {\n  increment: state =\u003e state + 1,\n  decrement: state =\u003e state - 1,\n});\n\nconst App = () =\u003e {\n  const [state, dispatch] = useReducer(reducer, initialState);\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003e{state}\u003c/div\u003e\n      \u003cbutton onClick={() =\u003e dispatch(increment())}\u003e+\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e dispatch(decrement())}\u003e-\u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n### createActions\n\n```ts\nimport { createActions } from 'use-case-reducers';\n\nconst actions = createActions(caseReducers);\n```\n\nIf 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.\n\n### createReducer\n\n```ts\nimport { createReducer } from 'use-case-reducers';\n\nconst reducer = createReducer(caseReducers);\n```\n\nThis function will return a reducer function generated by the `caseReducers` you pass in.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjason89521%2Fuse-case-reducers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjason89521%2Fuse-case-reducers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjason89521%2Fuse-case-reducers/lists"}