{"id":28968592,"url":"https://github.com/culturehq/react-state-mutations","last_synced_at":"2026-04-28T09:35:08.702Z","repository":{"id":38361156,"uuid":"132029928","full_name":"CultureHQ/react-state-mutations","owner":"CultureHQ","description":"Modify component state without race conditions.","archived":false,"fork":false,"pushed_at":"2023-01-25T10:02:17.000Z","size":3045,"stargazers_count":2,"open_issues_count":17,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-05-25T14:52:07.853Z","etag":null,"topics":["functional-programming","react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CultureHQ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-03T17:42:49.000Z","updated_at":"2021-12-31T10:11:37.000Z","dependencies_parsed_at":"2023-02-14T06:25:16.641Z","dependency_job_id":null,"html_url":"https://github.com/CultureHQ/react-state-mutations","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/CultureHQ/react-state-mutations","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CultureHQ%2Freact-state-mutations","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CultureHQ%2Freact-state-mutations/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CultureHQ%2Freact-state-mutations/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CultureHQ%2Freact-state-mutations/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CultureHQ","download_url":"https://codeload.github.com/CultureHQ/react-state-mutations/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CultureHQ%2Freact-state-mutations/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261641025,"owners_count":23188434,"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":["functional-programming","react"],"created_at":"2025-06-24T09:09:23.809Z","updated_at":"2026-04-28T09:35:08.646Z","avatar_url":"https://github.com/CultureHQ.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-state-mutations\n\n[![Build Status](https://github.com/CultureHQ/react-state-mutations/workflows/Main/badge.svg)](https://github.com/CultureHQ/react-state-mutations/actions)\n[![Package Version](https://img.shields.io/npm/v/react-state-mutations.svg)](https://www.npmjs.com/package/react-state-mutations)\n\nState updates in `React` [may be asynchronous](https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous). In the case that you're using the previous state to calculate the next state, you could run into race conditions when `React` attempts to batch your state changes together. The following example demonstrates the problem:\n\n```javascript\n// Warning! This is the bad example.\nimport React, { Component } from \"react\";\n\nclass Counter extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = { count: 0 };\n    this.handleClick = this.handleClick.bind(this);\n  }\n\n  handleClick() {\n    this.setState({ count: this.state.count + 1 });\n    this.setState({ count: this.state.count + 1 });\n  }\n\n  render() {\n    const { count } = this.state;\n    return (\n      \u003cbutton type=\"button\" onClick={this.handleClick}\u003e\n        {count}\n      \u003c/button\u003e\n    );\n  }\n}\n\nexport default Counter;\n```\n\nIn the example above, since both `setState` calls mutate the same key, those mutations can be merged together, and you may end up with it only incrementing each click by one since the last mutation will win. You can solve this by passing a function to `setState`, as those are executed sequentially and will not run over each other. This is demonstrated in the example below:\n\n```javascript\nimport React, { Component } from \"react\";\n\nclass Counter extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = { count: 0 };\n    this.handleClick = this.handleClick.bind(this);\n  }\n\n  handleClick() {\n    this.setState(({ count }) =\u003e ({ count: count + 1 }));\n    this.setState(({ count }) =\u003e ({ count: count + 1 }));\n  }\n\n  render() {\n    const { count } = this.state;\n    return (\n      \u003cbutton type=\"button\" onClick={this.handleClick}\u003e\n        {count}\n      \u003c/button\u003e\n    );\n  }\n}\n\nexport default Counter;\n```\n\nThe beauty of this approach is that you can begin to extract out the state mutation into a separate function that can then be reused. As in the following refactor:\n\n```javascript\nimport React, { Component } from \"react\";\n\nconst incrementCount = ({ count }) =\u003e ({ count: count + 1 });\n\nclass Counter extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = { count: 0 };\n    this.handleClick = this.handleClick.bind(this);\n  }\n\n  handleClick() {\n    this.setState(incrementCount);\n    this.setState(incrementCount);\n  }\n\n  render() {\n    const { count } = this.state;\n    return (\n      \u003cbutton type=\"button\" onClick={this.handleClick}\u003e\n        {count}\n      \u003c/button\u003e\n    );\n  }\n}\n\nexport default Counter;\n```\n\nThis is the basis for this library. The `increment` function is already defined for you, as well as various other utilities. This library additionally provides an easy interface for defining your own mutations that read from the previous state so that you never run into race conditions with your state mutations. Using `react-state-mutations`, the final result would look like:\n\n```javascript\nimport React, { Component } from \"react\";\nimport { increment } from \"react-state-mutations\";\n\nconst incrementCount = increment(\"count\");\n\nclass Counter extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = { count: 0 };\n    this.handleClick = this.handleClick.bind(this);\n  }\n\n  handleClick() {\n    this.setState(incrementCount);\n    this.setState(incrementCount);\n  }\n\n  render() {\n    const { count } = this.state;\n    return (\n      \u003cbutton type=\"button\" onClick={this.handleClick}\u003e\n        {count}\n      \u003c/button\u003e\n    );\n  }\n}\n\nexport default Counter;\n```\n\nYou can alternatively use this library in conjunction with the `useState` feature in React. To get the equivalent as the above example working, you can use:\n\n```javascript\nimport React, { useState } from \"react\";\nimport { incrementState } from \"react-state-mutations\";\n\nconst Counter = () =\u003e {\n  const [count, setCount] = useState(0);\n  const onClick = () =\u003e {\n    setCount(incrementState);\n    setCount(incrementState);\n  };\n\n  return (\n    \u003cbutton type=\"button\" onClick={onClick}\u003e\n      {count}\n    \u003c/button\u003e\n  );\n};\n\nexport default Counter;\n```\n\nOr, you could use the built in `useIncrement` hook, as in:\n\n```javascript\nimport React from \"react\";\nimport { useIncrement } from \"react-state-mutations\";\n\nconst Counter = () =\u003e {\n  const [count, onIncrement] = useIncrement(0);\n  const onClick = () =\u003e {\n    onIncrement();\n    onIncrement();\n  };\n\n  return (\n    \u003cbutton type=\"button\" onClick={onClick}\u003e\n      {count}\n    \u003c/button\u003e\n  );\n};\n\nexport default Counter;\n```\n\n## Getting started\n\nInstall this package through `npm` (`npm install react-state-mutations --save`) or `yarn` (`yarn add react-state-mutations`). You can then import and use the mutations from within your components.\n\nIn addition with the ability to create your own mutations, this package ships with some pre-built mutations, listed below.\n\n- [`append`](#append)\n- [`concat`](#concat)\n- [`cycle`](#cycle)\n- [`decrement`](#decrement)\n- [`direct`](#direct)\n- [`filter`](#filter)\n- [`increment`](#increment)\n- [`map`](#map)\n- [`mutate`](#mutate)\n- [`prepend`](#prepend)\n- [`toggle`](#toggle)\n\nThere is also an equivalent version of each of these mutations that works on standalone values. This can be used in conjunction with React's `useState` to manipulate state in a safe way. The equivalent version is named the same, with `State` appended onto the end. i.e., the equivalent mutation for `toggle` is `toggleState`, which will effectively perform `value =\u003e !value`. Finally, there are hooks built in that use those mutations, so in `useToggle` for the above example.\n\n### `append`\n\nAppends a value to a list, as in the example:\n\n```javascript\nimport { append } from \"react-state-mutations\";\n\nconst appendStudent = append(\"students\");\n\nconst prevState = { students: [{ name: \"Harry\" }, { name: \"Hermione\" }] };\nconst nextState = appendStudent({ name: \"Ron\" })(prevState);\n// =\u003e { students: [{ name: \"Harry\" }, { name: \"Hermione\" }, { name: \"Ron\" }] }\n```\n\nWith single values:\n\n```javascript\nimport { appendState } from \"react-state-mutations\";\n\nconst prevState = [{ name: \"Harry\" }, { name: \"Hermione\" }];\nconst nextState = appendState({ name: \"Ron\" })(prevState);\n// =\u003e [{ name: \"Harry\" }, { name: \"Hermione\" }, { name: \"Ron\" }]\n```\n\nWith hooks:\n\n```javascript\nimport { useAppend } from \"react-state-mutations\";\n\nconst Students = () =\u003e {\n  const [students, onAppend] = useAppend([\n    { name: \"Harry\" },\n    { name: \"Hermione\" }\n  ]);\n\n  // sometime later...\n  onAppend({ name: \"Ron\" });\n};\n```\n\nWith TypeScript, `append`, `appendState`, and `useAppend` all accept an additional type argument for specifying which type the array will hold, as in:\n\n```typescript\ninterface Student {\n  name: string;\n}\n\nappend\u003cStudent\u003e(\"students\");\n```\n\n### `concat`\n\nConcatentate two lists, as in the example:\n\n```javascript\nimport { concat } from \"react-state-mutations\";\n\nconst concatStudents = concat(\"students\");\n\nconst prevState = { students: [{ name: \"Harry\" }, { name: \"Hermione\" }] };\nconst nextState = concatStudents([{ name: \"Ron\" }, { name: \"Ginny\" }])(\n  prevState\n);\n// =\u003e { students: [{ name: \"Harry\" }, { name: \"Hermione\" }, { name: \"Ron\" }, { name: \"Ginny\" }] }\n```\n\nWith single values:\n\n```javascript\nimport { concatState } from \"react-state-mutations\";\n\nconst prevState = [{ name: \"Harry\" }, { name: \"Hermione\" }];\nconst nextState = concatState([{ name: \"Ron\" }, { name: \"Ginny\" }])(prevState);\n// =\u003e [{ name: \"Harry\" }, { name: \"Hermione\" }, { name: \"Ron\" }, { name: \"Ginny\" }]\n```\n\nWith hooks:\n\n```javascript\nimport { useConcat } from \"react-state-mutations\";\n\nconst Students = () =\u003e {\n  const [students, onConcat] = useConcat([\n    { name: \"Harry\" },\n    { name: \"Hermione\" }\n  ]);\n\n  // sometime later...\n  onConcat([{ name: \"Ron\" }, { name: \"Ginny\" }]);\n};\n```\n\nWith TypeScript, `concat`, `concatState`, and `useConcat` all accept an additional type argument for specifying which type the array will hold, as in:\n\n```typescript\ninterface Student {\n  name: string;\n}\n\nconcat\u003cStudent\u003e(\"students\");\n```\n\n### `cycle`\n\nCycles through a list of values, as in the example:\n\n```javascript\nimport { cycle } from \"react-state-mutations\";\n\nconst cycleHouse = cycle(\"house\");\nconst visitNextHogwartsHouse = cycleHouse([\n  \"Gryffindor\",\n  \"Hufflepuff\",\n  \"Ravenclaw\",\n  \"Slytherin\"\n]);\n\nconst prevState = { house: \"Gryffindor\" };\nlet nextState = visitNextHogwartsHouse(prevState);\n// =\u003e { house: \"Hufflepuff\" }\n\nnextState = visitNextHogwartsHouse(nextState);\n// =\u003e { house: \"Ravenclaw\" }\n\nnextState = visitNextHogwartsHouse(nextState);\n// =\u003e { house: \"Slytherin\" }\n\nnextState = visitNextHogwartsHouse(nextState);\n// =\u003e { house: \"Gryffindor\" }\n```\n\nWith single values:\n\n```javascript\nimport { cycleState } from \"react-state-mutations\";\n\nconst visitNextHogwartsHouse = cycleState([\n  \"Gryffindor\",\n  \"Hufflepuff\",\n  \"Ravenclaw\",\n  \"Slytherin\"\n]);\n\nconst prevState = \"Gryffindor\";\nlet nextState = visitNextHogwartsHouse(prevState);\n// =\u003e \"Hufflepuff\"\n\nnextState = visitNextHogwartsHouse(nextState);\n// =\u003e \"Ravenclaw\"\n\nnextState = visitNextHogwartsHouse(nextState);\n// =\u003e \"Slytherin\"\n\nnextState = visitNextHogwartsHouse(nextState);\n// =\u003e \"Gryffindor\"\n```\n\nWith hooks:\n\n```javascript\nimport { useCycle } from \"react-state-mutations\";\n\nconst HogwartsHouses = () =\u003e {\n  const [house, onCycle] = useCycle([\n    \"Gryffindor\",\n    \"Hufflepuff\",\n    \"Ravenclaw\",\n    \"Slytherin\"\n  ]);\n\n  // sometime later...\n  onCycle();\n};\n```\n\nWith TypeScript, `cycle`, `cycleState`, and `useCycle` all accept an additional type argument for specifying which type the array will hold, as in:\n\n```typescript\ntype House = string;\n\ncycle\u003cHouse\u003e(\"house\");\n```\n\n### `decrement`\n\nDecrements a value, as in the example:\n\n```javascript\nimport { decrement } from \"react-state-mutations\";\n\nconst destroyHorcrux = decrement(\"horcruxes\");\n\nconst prevState = { horcruxes: 7 };\nconst nextState = destroyHorcrux(prevState);\n// =\u003e { count: 6 }\n```\n\nWith single values:\n\n```javascript\nimport { decrementState } from \"react-state-mutations\";\n\nconst prevState = 7;\nconst nextState = decrementState(prevState);\n// =\u003e 6\n```\n\nWith hooks:\n\n```javascript\nimport { useDecrement } from \"react-state-mutations\";\n\nconst Horcruxes = () =\u003e {\n  const [count, onDecrement] = useDecrement(7);\n\n  // sometime later...\n  onDecrement();\n};\n```\n\nWith TypeScript, `decrement`, `decrementState`, and `useDecrement` enforce the `number` type on arguments.\n\n### `direct`\n\nDirectly modifies a value. This is mainly valuable when used with `combineMutations`, as otherwise you could just pass the value to `setState` as normal. The code below uses `combineMutations` with others as an example:\n\n```javascript\nimport { direct, toggle, combineMutations } from \"react-state-mutations\";\n\nconst getCake = direct(\"cake\");\nconst becomeAWizard = combineMutations(toggle(\"wizard\"), getCake);\n\nconst prevState = { wizard: false, cake: null };\nconst nextState = becomeAWizard(\"chocolate\")(prevState);\n// =\u003e { wizard: true, cake: \"chocolate\" }\n```\n\nWith single values:\n\n```javascript\nimport { directState } from \"react-state-mutations\";\n\nconst getCake = directState(\"cake\");\n\nconst prevState = null;\nconst nextState = getCake(prevState);\n// =\u003e \"cake\"\n```\n\nWith TypeScript, `direct` and `directState` each accept an additional type argument for specifying which type of object will be assigned into the state.\n\n### `filter`\n\nFilters a list, as in the example:\n\n```javascript\nimport { filter } from \"react-state-mutations\";\n\nconst filterStudents = filter(\"students\");\nconst findGryffindors = filterStudents(({ house }) =\u003e house === \"Gryffindor\");\n\nconst prevState = {\n  students: [\n    { name: \"Harry\", house: \"Gryffindor\" },\n    { name: \"Cedric\", house: \"Hufflepuff\" },\n    { name: \"Pansy\", house: \"Slytherin\" }\n  ]\n};\n\nconst nextState = findGryffindors(prevState);\n// =\u003e { students: [{ name: \"Harry\", house: \"Gryffindor\" }] }\n```\n\nWith single values:\n\n```javascript\nimport { filterState } from \"react-state-mutations\";\n\nconst findGryffindors = filterState(({ house }) =\u003e house === \"Gryffindor\");\n\nconst prevState = [\n  { name: \"Harry\", house: \"Gryffindor\" },\n  { name: \"Cedric\", house: \"Hufflepuff\" },\n  { name: \"Pansy\", house: \"Slytherin\" }\n];\n\nconst nextState = findGryffindors(prevState);\n// =\u003e [{ name: \"Harry\", house: \"Gryffindor\" }]\n```\n\nWith hooks:\n\n```javascript\nimport { useFilter } from \"react-state-mutations\";\n\nconst Students = () =\u003e {\n  const [students, onFilter] = useFilter([\n    { name: \"Harry\", house: \"Gryffindor\" },\n    { name: \"Cedric\", house: \"Hufflepuff\" },\n    { name: \"Pansy\", house: \"Slytherin\" }\n  ]);\n\n  // sometime later...\n  onFilter(({ house }) =\u003e house === \"Gryffindor\");\n};\n```\n\nWith TypeScript, `filter`, `filterState`, and `useFilter` all accept an additional type argument `T` for specifying which type the array will hold. Additionally the filter function argument is enforced to be of the type `((value: T) =\u003e boolean)`, as in:\n\n```typescript\ninterface Student {\n  name: string;\n  house: string;\n}\n\nfilterState\u003cStudent\u003e(({ house }) =\u003e house === \"Gryffindor\");\n```\n\n### `increment`\n\nIncrements a value, as in the example:\n\n```javascript\nimport { increment } from \"react-state-mutations\";\n\nconst upgradeBroom = increment(\"Nimbus\");\n\nconst prevState = { Nimbus: 2000 };\nconst nextState = upgradeBroom(prevState);\n// =\u003e { Nimbus: 2001 }\n```\n\nWith single values:\n\n```javascript\nimport { incrementState } from \"react-state-mutations\";\n\nconst prevState = 2000;\nconst nextState = incrementState(prevState);\n// =\u003e 2001\n```\n\nWith hooks:\n\n```javascript\nimport { useIncrement } from \"react-state-mutations\";\n\nconst Nimbus = () =\u003e {\n  const [version, onIncrement] = useIncrement(2000);\n\n  // sometime later...\n  onIncrement();\n};\n```\n\nWith TypeScript, `increment`, `incrementState`, and `useDecrement` enforce the `number` type on arguments.\n\n### `map`\n\nMaps over a list, as in the example:\n\n```javascript\nimport { map } from \"react-state-mutations\";\n\nconst mapStudents = map(\"students\");\nconst graduateStudents = mapStudents(({ year, ...rest }) =\u003e ({\n  year + 1, ...rest\n}));\n\nconst prevState = {\n  students: [\n    { name: \"Harry\", year: 2 },\n    { name: \"Ginny\", year: 1 }\n  ]\n};\n\nconst nextState = graduateStudents(prevState);\n// =\u003e { students: [{ name: \"Harry\", year: 3 }, { name: \"Ginny\", year: 2 }] }\n```\n\nWith single values:\n\n```javascript\nimport { mapState } from \"react-state-mutations\";\n\nconst graduateStudents = mapState(({ year, ...rest }) =\u003e ({\n  year + 1, ...rest\n}));\n\nconst prevState = [\n  { name: \"Harry\", year: 2 },\n  { name: \"Ginny\", year: 1 }\n];\n\nconst nextState = graduateStudents(prevState);\n// =\u003e [{ name: \"Harry\", year: 3 }, { name: \"Ginny\", year: 2 }]\n```\n\nWith hooks:\n\n```javascript\nimport { useMap } from \"react-state-mutations\";\n\nconst Students = () =\u003e {\n  const [students, onMap] = useMap([\n    { name: \"Harry\", year: 2 },\n    { name: \"Ginny\", year: 1 }\n  ]);\n\n  // sometime later...\n  onMap(({ year, ...rest }) =\u003e ({ year + 1, ...rest }));\n};\n```\n\nWith TypeScript, `map`, `mapState`, and `useMap` all accept an additional type argument `T` for specifying which type the array will hold. Additionally the map function argument is enforced to be of the type `((value: T) =\u003e T)`, as in:\n\n```typescript\ninterface Student {\n  name: string;\n  year: number;\n}\n\nmapState\u003cStudent\u003e(({ year, ...rest }) =\u003e ({ year + 1, ...rest }));\n```\n\n### `mutate`\n\nMutates a value, as in the example:\n\n```javascript\nimport { mutate } from \"react-state-mutations\";\n\nconst mutateLupin = mutate(\"Lupin\");\nconst fullMoon = mutateLupin({ status: \"Wolf\" });\n\nconst prevState = { Lupin: { status: \"Man\", role: \"Professor\" } };\nconst nextState = fullMoon(prevState);\n// =\u003e { Lupin: { status: \"Wolf\", role: \"Professor\" } }\n```\n\nWith single values:\n\n```javascript\nimport { mutateState } from \"react-state-mutations\";\n\nconst fullMoon = mutateState({ status: \"Wolf\" });\n\nconst prevState = { status: \"Man\", role: \"Professor\" };\nconst nextState = fullMoon(prevState);\n// =\u003e { status: \"Wolf\", role: \"Professor\" }\n```\n\nWith TypeScript, the object being used to mutate is enforced to be of type `object`.\n\n### `prepend`\n\nPrepends a value to a list, as in the example:\n\n```javascript\nimport { prepend } from \"react-state-mutations\";\n\nconst prependStudent = prepend(\"students\");\n\nconst prevState = { students: [{ name: \"Harry\" }, { name: \"Hermione\" }] };\nconst nextState = prependStudent({ name: \"Ron\" })(prevState);\n// =\u003e { students: [{ name: \"Ron\" }, { name: \"Harry\" }, { name: \"Hermione\" }] }\n```\n\nWith single values:\n\n```javascript\nimport { prependState } from \"react-state-mutations\";\n\nconst prevState = [{ name: \"Harry\" }, { name: \"Hermione\" }];\nconst nextState = prependState({ name: \"Ron\" })(prevState);\n// =\u003e [{ name: \"Ron\" }, { name: \"Harry\" }, { name: \"Hermione\" }]\n```\n\nWith hooks:\n\n```javascript\nimport { usePrepend } from \"react-state-mutations\";\n\nconst Students = () =\u003e {\n  const [students, onPrepend] = usePrepend([\n    { name: \"Harry\" },\n    { name: \"Hermione\" }\n  ]);\n\n  // sometime later...\n  onPrepend({ name: \"Ron\" });\n};\n```\n\nWith TypeScript, `prepend`, `prependState`, and `usePrepend` all accept an additional type argument for specifying which type the array will hold, as in:\n\n```typescript\ninterface Student {\n  name: string;\n}\n\nprepend\u003cStudent\u003e(\"students\");\n```\n\n### `toggle`\n\nToggles a boolean value, as in the example:\n\n```javascript\nimport { toggle } from \"react-state-mutations\";\n\nconst toggleWizard = toggle(\"wizard\");\n\nconst prevState = { wizard: false };\nconst nextState = toggleWizard(prevState);\n// =\u003e { wizard: true }\n```\n\nWith single values:\n\n```javascript\nimport { toggleState } from \"react-state-mutations\";\n\nconst prevState = false;\nconst nextState = toggleState(prevState);\n// =\u003e true\n```\n\nWith hooks:\n\n```javascript\nimport { useToggle } from \"react-state-mutations\";\n\nconst WizardStatus = () =\u003e {\n  const [isWizard, onToggle] = useToggle(false);\n\n  // sometime later, with Hagrid...\n  onToggle();\n};\n```\n\nWith TypeScript, `toggle`, `toggleState`, and `useToggle` enforce the `boolean` type on arguments.\n\n## Advanced\n\nThere are a couple of advanced functions, for creating your own mutations, combining multiple mutations into one function, and creating your own hooks.\n\n### `makeStandaloneMutation`\n\nCreates a mutation that modifies state. Takes as an argument a function that accepts a value and returns the modified value. As in the example:\n\n```javascript\nimport { makeStandaloneMutation } from \"react-state-mutations\";\n\nconst encrypt = makeStandaloneMutation(value =\u003e (\n  value.split(\"\").reverse().join(\"\")\n));\n\nconst encryptName = encrypt(\"name\");\n\nconst prevState = { name: \"Harry\" };\nconst nextState = encryptName(prevState);\n// =\u003e { name: \"yrraH\" }\n```\n\nWith Typescript, `makeStandaloneMutation` accepts an additional type argument for specifying which type of value will be mutated. For example:\n\n```typescript\nconst encrypt = makeStandaloneMutation\u003cstring\u003e(value =\u003e (\n  value.split(\"\").reverse().join(\"\")\n));\n```\n\n### `makeArgumentMutation`\n\nCreates a mutation that is a function that takes one argument, that itself returns a function that modifies state. Takes as a function that accepts a value that returns a return that accepts the state and returns the modifies value. As in the example:\n\n```javascript\nimport { makeArgumentMutation } from \"react-state-mutations\";\n\nconst add = makeArgumentMutation(increment =\u003e value =\u003e value + increment);\nconst flyUp100Feet = add(\"currentHeight\")(100);\n\nconst prevState = { currentHeight: 0 };\nconst nextState = flyUp100Feet(prevState);\n// =\u003e { currentHeight: 100 }\n```\n\nWith TypeScript, `makeArgumentMutation` accepts two type arguments, for specifying which type of value will be mutated and for specifying the type of the argument to be passed in. For example:\n\n```typescript\nconst add = makeArgumentMutation\u003cnumber, number\u003e(increment =\u003e (\n  value =\u003e value + increment\n));\n```\n\n### `combineMutations`\n\nCombines multiple mutations into a single mutation function. Takes any number of arguments and returns a singular mutation created out of the combination of them all. Can accept either mutations created through `react-state-mutations`, or plain objects that are meant to be directly setting state.\n\nIf any \"argument\" mutations are passed in, `combineMutations` will return a function that accepts any number of arguments, that themselves will be passed to the mutations in the order in which they appear in the list given to `combineMutations`. As in the example:\n\n```javascript\nimport { append, increment } from \"react-state-mutations\";\n\nconst addToTeam = combineMutations(append(\"players\"), increment(\"roster\"));\n\nconst prevState = {\n  players: [{ name: \"Angelina\" }, { name: \"Alicia\" }],\n  roster: 2\n};\n\nconst nextState = addToTeam({ name: \"Katie\" })(prevState);\n// =\u003e {\n//   players: [{ name: \"Angelina\" }, { name: \"Alicia\" }, { name: \"Katie\" }],\n//   roster: 3\n// };\n```\n\nIf all of the mutations that are passed in are \"standalone\" mutations, then\n`combineMutations` will return a function that simply accepts and modifies\nthe state. As in the example:\n\n```javascript\nimport { toggle, increment } from \"react-state-mutations\";\n\nconst becomeAWizard = combineMutations(toggle(\"wizard\"), increment(\"wizards\"));\n\nconst prevState = { wizard: false, wizards: 0 };\nconst nextState = mutation(prevState);\n// =\u003e { wizard: true, wizards: 1 };\n```\n\nYou can additionally pass plain objects into `combineMutations` that are\nintended to directly set state. In this case they will be folded into the\nresultant function and treated as \"standalone\" mutations that do not accept\narguments. As in the example:\n\n```javascript\nimport { combineMutations, makeArgumentMutation } from \"react-state-mutations\";\n\nconst startFlying = combineMutations(\n  makeArgumentMutation(height =\u003e value =\u003e value + height),\n  { flying: true }\n);\n\nconst prevState = { height: 0, flying: false };\nconst nextState = startFlying(100)(prevState);\n// =\u003e { height: 100, flying: true };\n```\n\n### `makeStandaloneHook`\n\nCreates a reusable hook based on a mutation that requires no further input. `makeStandaloneHook` takes two arguments, the first behind the mutation and the second being the default initial value. For example, if you wanted to create a hook that would always multiply the previous value by 2, you could:\n\n```javascript\nimport { makeStandaloneHook } from \"react-state-mutations\";\n\nconst useDouble = makeStandaloneHook(value =\u003e value * 2, 1);\n```\n\nThen, you could use `useDouble` in your components as any other hooks, as in:\n\n```javascript\nconst DoubleDouble = () =\u003e {\n  const [value, onDouble] = useDouble();\n\n  return (\n    \u003cbutton type=\"button\" onClick={onDouble}\u003e\n      {value}\n    \u003c/button\u003e\n  );\n};\n```\n\nYou can also pass a value to `useDouble` in this example to start at a certain value.\n\nWith TypeScript, `makeStandaloneHook` accepts an additional type argument for specifying which kind of value will be stored in state. For example,\n\n```typescript\nconst useDouble = makeStandaloneHook\u003cnumber\u003e(value =\u003e value * 2, 1);\n```\n\n### `makeArgumentHook`\n\nCreates a reusable hook based on a mutation that requires one argument. `makeArgumentHook` takes two arguments (the same as `makeStandaloneHook`), the first behind the mutation and the second being the default initial value. For example, if you wanted to create a hook that would count up values in succession, you could:\n\n```javascript\nimport { makeArgumentHook } from \"react-state-mutations\";\n\nconst useAdder = makeArgumentHook(object =\u003e value =\u003e value + object, 0);\n```\n\nThen you could use `useAdder` in your components as any other hooks, as in:\n\n```javascript\nimport { useCallback, useState } from \"react\";\n\nconst Sum = () =\u003e {\n  const [number, setNumber] = useState(\"\");\n  const onChange = useCallback(event =\u003e setNumber(event.target.value), []);\n\n  const [value, onAdd] = useAdder();\n  const onClick = useCallback(() =\u003e onAdd(number), [number]);\n\n  return (\n    \u003c\u003e\n      \u003cinput type=\"number\" value={value} onChange={onChange} /\u003e\n      \u003cbutton type=\"button\" onClick={onClick}\u003e\n        Add\n      \u003c/button\u003e\n    \u003c/\u003e\n  );\n};\n```\n\nWith TypeScript, `makeArgumentHook` accepts two additional type arguments for specifying which kind of value will be stored in state, and which kind of value will be accepted as an argument. For example,\n\n```typescript\nconst useAdder = makeArgumentHook\u003cnumber, number\u003e(\n  object =\u003e value =\u003e value + object, 0\n);\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/CultureHQ/react-state-mutations.\n\n## License\n\nThe code is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fculturehq%2Freact-state-mutations","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fculturehq%2Freact-state-mutations","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fculturehq%2Freact-state-mutations/lists"}