{"id":13451970,"url":"https://github.com/revelcw/react-hooks-helper","last_synced_at":"2025-03-23T19:33:22.085Z","repository":{"id":38862759,"uuid":"162724734","full_name":"revelcw/react-hooks-helper","owner":"revelcw","description":"A custom React Hooks library that gives you custom hooks for your code.","archived":true,"fork":false,"pushed_at":"2023-01-03T15:47:13.000Z","size":1765,"stargazers_count":244,"open_issues_count":22,"forks_count":17,"subscribers_count":7,"default_branch":"develop","last_synced_at":"2024-09-17T01:41:46.796Z","etag":null,"topics":["custom-hook","form","hooks","react","react-hooks","step","wizard","wizard-steps"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/revelcw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-21T14:42:13.000Z","updated_at":"2024-02-01T02:39:23.000Z","dependencies_parsed_at":"2023-02-01T07:30:56.531Z","dependency_job_id":null,"html_url":"https://github.com/revelcw/react-hooks-helper","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/revelcw%2Freact-hooks-helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/revelcw%2Freact-hooks-helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/revelcw%2Freact-hooks-helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/revelcw%2Freact-hooks-helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/revelcw","download_url":"https://codeload.github.com/revelcw/react-hooks-helper/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221900705,"owners_count":16898986,"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":["custom-hook","form","hooks","react","react-hooks","step","wizard","wizard-steps"],"created_at":"2024-07-31T07:01:08.700Z","updated_at":"2024-10-28T18:30:26.378Z","avatar_url":"https://github.com/revelcw.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# react-hooks-helper\n\n[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors)\n\nA custom [React Hooks](https://reactjs.org/docs/hooks-overview.html) library that gives you custom\nhooks for your code.\n\n[![npm version](https://badge.fury.io/js/react-hooks-helper.svg)](https://badge.fury.io/js/react-hooks-helper)\n\n![react-hooks-helper](https://user-images.githubusercontent.com/29359616/50549517-422f4800-0c2c-11e9-9d5c-380954b0d05e.png)\n\n\u003e 🧙‍ `useStep` is a multi-purpose step wizard. Build an image carousel!\n\u003e\n\u003e 📋 `useForm` for dead simple form control with nested object support.\n\u003e\n\u003e 🚦 `useTrafficLight` easily build a fun traffic light component.\n\u003e\n\u003e ‼ `useNot` to simplify toggling `true` / `false` without lambda functions.\n\u003e\n\u003e 🐐 Full 100% test coverage!\n\u003e\n\u003e 🔥 Blazing fast!\n\n## Requirement ⚠️\n\nTo use `react-hooks-helper`, you must use `react@16.8`.\n\n## Installation\n\n```sh\n$ npm i react-hooks-helper\n```\n\n## Usage\n\n```js\nconst { isPaused, index, step, navigation } = useStep(config);\nconst [{ foo, bar }, setForm] = useForm({ foo, bar });\nconst currentValue = useTrafficLight(initialIndex, durations);\nconst [bar, notBar] = useNot(bool);\n```\n\n## Examples\n\n### useStep\n\nThe new `useStep` Hook is the new `useTrafficLight` and is a more general step wizard.\nYou can use it to simplify many tasks, such as a multi-page input form, or an image carousel.\n\nIt has an auto advance function, or control manually by calling `previous` and/or `next`.\n\n#### Usage\n\n```js\nconst { isPaused, index, step, navigation } = useStep(config);\n```\n\n#### Config\n\nYou pass `useStep` a configuration object containing the following (\\* = required).\n\n| Key                   | Description                                                                                                                                                                                                           |\n| :-------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `steps`\\*             | Either an array containing the steps to process or an integer specifying the number of steps.                                                                                                                         |\n| `initialStep`         | The starting step—either a string id or an index. Default = 0.                                                                                                                                                        |\n| `autoAdvanceDuration` | If you wish the steps to auto-advance, specify the number of milliseconds. You can also include an `autoAdvanceDuration` in each `step` in your `steps` array, if you wish to have different durations for each step. |\n\n#### Return object\n\n| Key                   | Description                                       |\n| :-------------------- | :------------------------------------------------ |\n| `index`               | A number containing the current step index.       |\n| `step`                | The current `step` object from the `steps` array. |\n| `navigation`          | A `navigation` object (see below).                |\n| `isPaused`            | `true` if the `autoAdvanceDuration` is paused.    |\n| `autoAdvanceDuration` | Duration of the current auto-advance.             |\n\n#### Navigation object\n\nThe `navigation` object returned from `useStep` contains control callback functions as follows.\n\n| Key        | Description                                                                                            |\n| :--------- | :----------------------------------------------------------------------------------------------------- |\n| `previous` | Call to navigate to the previous item index. Wraps from the first item to the last item.               |\n| `next`     | Call to navigate to the next item index. Wraps from the last item to the first item.                   |\n| `go`       | Call to navigate to a specific step by `id` or by `index`. Example: `go(2)` or `go('billing-address')` |\n| `pause`    | Pause auto-advance navigation.                                                                         |\n| `play`     | Play auto-advance navigation once it has been paused.                                                  |\n\n#### Example\n\nThere's a simple multi-step control with 3 \"pages\".\nYou use the \"Previous\" and \"Next\" buttons to navigate.\n\n```js\nfunction App() {\n  const {\n    index,\n    navigation: { previous, next },\n  } = useStep({ steps: 3 });\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eHello CodeSandbox\u003c/h1\u003e\n\n      {index === 0 \u0026\u0026 \u003cdiv\u003eThis is step 1\u003c/div\u003e}\n      {index === 1 \u0026\u0026 \u003cdiv\u003eThis is step 2\u003c/div\u003e}\n      {index === 2 \u0026\u0026 \u003cdiv\u003eThis is step 3\u003c/div\u003e}\n\n      \u003cdiv\u003e\n        \u003cbutton disabled={index === 0} onClick={previous}\u003e\n          Previous\n        \u003c/button\u003e\n        \u003cbutton disabled={index === 2} onClick={next}\u003e\n          Next\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n#### Live demo\n\nYou can view/edit a photo carousel on CodeSandbox.\nIt automatically advances after 5 seconds. You can also click previous/next, or\nnavigate directly to a particular image.\n\n[![image](https://user-images.githubusercontent.com/887639/51504518-73281600-1daf-11e9-9509-07ca1145c291.png)](https://codesandbox.io/s/31228l0rnm)\n\n[![Edit Carousel using hooks (rhh demo)](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/31228l0rnm)\n\n### useForm\n\n`useForm` is for an advanced search, sign-up form, etc, something with a lot of text felds, because\nyou only need to use one hook. Wereas on the otherwise you would need many `useState` hooks.\n\n---\n\n#### Before\n\nRight here is some code for a sign-up form. As you can see it is using two `useState` hooks and we\nneed a lambda function to change it.\n\n```jsx\nfunction App() {\n  const [firstName, setFirstName] = useState(\"\");\n  const [lastName, setLastName] = useState(\"\");\n  const [gender, setGender] = useState(\"Male\");\n  const [isAccept, setAcceptToC] = useState(false);\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cinput\n        type=\"text\"\n        value={firstName}\n        onChange={(ev) =\u003e {\n          setFirstName(ev.target.value);\n        }}\n      /\u003e\n      \u003cdiv\u003e{firstName}\u003c/div\u003e\n      \u003cinput\n        type=\"text\"\n        value={lastName}\n        onChange={(ev) =\u003e {\n          setLastName(ev.target.value);\n        }}\n      /\u003e\n      \u003cdiv\u003e{lastName}\u003c/div\u003e\n      \u003cdiv className=\"radio-group\"\u003e\n        \u003cdiv className=\"radio\"\u003e\n          \u003cinput\n            type=\"radio\"\n            value=\"Female\"\n            checked={gender === \"Female\"}\n            onChange={(ev) =\u003e {\n              setGender(ev.target.value);\n            }}\n          /\u003e{\" \"}\n          Female\n        \u003c/div\u003e\n        \u003cdiv className=\"radio\"\u003e\n          \u003cinput\n            type=\"radio\"\n            value=\"Male\"\n            checked={gender === \"Male\"}\n            onChange={(ev) =\u003e {\n              setGender(ev.target.value);\n            }}\n          /\u003e{\" \"}\n          Male\n        \u003c/div\u003e\n        \u003cdiv\u003eSelected Gender: {gender}\u003c/div\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e\n        \u003cdiv className=\"checkbox\"\u003e\n          \u003cinput\n            type=\"checkbox\"\n            value=\"true\"\n            checked={isAccept === \"true\"}\n            onChange={(ev) =\u003e {\n              setAcceptToC(ev.target.checked);\n            }}\n          /\u003e{\" \"}\n          I accept and agree Terms \u0026amp; Conditions.\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n#### After\n\n```jsx\nfunction App() {\n  const [{ firstName, lastName, gender, isAccept }, setValue] = useForm({\n    firstName: \"\",\n    lastName: \"\",\n    gender: \"Male\",\n    isAccept: false,\n  });\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cinput\n        type=\"text\"\n        value={firstName}\n        name=\"firstName\"\n        onChange={setValue}\n      /\u003e\n      \u003cdiv\u003e{firstName}\u003c/div\u003e\n      \u003cinput type=\"text\" value={lastName} name=\"lastName\" onChange={setValue} /\u003e\n      \u003cdiv\u003e{lastName}\u003c/div\u003e\n      \u003cdiv className=\"radio-group\"\u003e\n        \u003cdiv className=\"radio\"\u003e\n          \u003cinput\n            type=\"radio\"\n            value=\"Female\"\n            checked={gender === \"Female\"}\n            onChange={setValue}\n          /\u003e{\" \"}\n          Female\n        \u003c/div\u003e\n        \u003cdiv className=\"radio\"\u003e\n          \u003cinput\n            type=\"radio\"\n            value=\"Male\"\n            checked={gender === \"Male\"}\n            onChange={setValue}\n          /\u003e{\" \"}\n          Male\n        \u003c/div\u003e\n        \u003cdiv\u003eSelected Gender: {gender}\u003c/div\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e\n        \u003cdiv className=\"checkbox\"\u003e\n          \u003cinput\n            type=\"checkbox\"\n            value=\"true\"\n            checked={isAccept === \"true\"}\n            onChange={setValue}\n          /\u003e{\" \"}\n          I accept and agree Terms \u0026amp; Conditions.\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nYou see `useForm` takes the name of your `input` and changes the object, so you only have to create\none `useForm`. You can have as many items in the object, and this allows many inputs, but with still\n**_one_** `useForm`. And it eliminates the use of a lambda function.\n\n#### Nest objects\n\n`useForm` also supports nested objects. This is useful for things like `billing.city` and `shipping.city`.\n\nIn your markup, you simply add the dots in the `name` field like this.\n\n```html\n\u003cinput\n  type=\"text\"\n  value=\"{billing.city}\"\n  name=\"billing.city\"\n  onChange=\"{setValue}\"\n/\u003e\n```\n\n#### Live demo\n\n[![Edit useForm (rhh demo)](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/useform-rhh-demo-4jy0pxxxo0)\n\n### \u003ca id=\"usetrafficlight\"\u003e \u003c/a\u003e useTrafficLight\n\n---\n\n#### Before\n\n```jsx\nconst lightDurations = [5000, 4000, 1000];\n\nconst BeforeTrafficLight = ({ initialColor }) =\u003e {\n  const [colorIndex, setColorIndex] = useState(initialColor);\n\n  useEffect(() =\u003e {\n    const timer = setTimeout(() =\u003e {\n      setColorIndex((colorIndex + 1) % 3);\n    }, lightDurations[colorIndex]);\n    return () =\u003e clearTimeout(timer);\n  }, [colorIndex]);\n\n  return (\n    \u003cdiv className=\"traffic-light\"\u003e\n      \u003cLight color=\"#f00\" active={colorIndex === 0} /\u003e\n      \u003cLight color=\"#ff0\" active={colorIndex === 2} /\u003e\n      \u003cLight color=\"#0c0\" active={colorIndex === 1} /\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n#### After\n\n```jsx\nconst AfterTrafficLight = ({ initialColor }) =\u003e {\n  const colorIndex = useTrafficLight(initialColor, [5000, 4000, 1000]);\n\n  return (\n    \u003cdiv className=\"traffic-light\"\u003e\n      \u003cLight color=\"#f00\" active={colorIndex === 0} /\u003e\n      \u003cLight color=\"#ff0\" active={colorIndex === 2} /\u003e\n      \u003cLight color=\"#0c0\" active={colorIndex === 1} /\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n#### Live demo\n\n[![Edit Traffic light using hooks (rhh demo)](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/zqo981j4ym)\n\n### useNot\n\n`useNot` is a toggle function for React components.\n\n---\n\nHere is a simple App that toggles a value to produce either a **blue** or a **red** square.\n\n#### \u003ca id=\"useNotBefore\"\u003e\u003c/a\u003eBefore\n\n```jsx\nfunction App() {\n  const [value, setValue] = useState(false);\n  return (\n    \u003cdiv\n      onClick={ value =\u003e (\n        setValue( !value )\n      )}\n      style={{\n        width: 100,\n        height: 100,\n        backgroundColor: value ? 'red' : 'blue'\n      }}\n    /\u003e\n  );\n```\n\n#### After\n\n```jsx\nfunction App() {\n  const [value, notValue] = useNot(false);\n  return (\n    \u003cdiv\n      onClick={notValue}\n      style={{\n        width: 100,\n        height: 100,\n        backgroundColor: value ? \"red\" : \"blue\",\n      }}\n    /\u003e\n  );\n}\n```\n\n`value`, a boolean, is a variable. `notValue`function that nots the value from `true` to `false` and\nvise versa. Notice the `notValue` is not a lambda function, like in the **[before](#useNotBefore)**\n\n#### Live demo\n\n[![Edit useNot  (rhh demo)](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rwk86po7rn)\n\n## My Coding Journey\n\nOn Dec 18, 2017, I did a talk at [ReactNYC](https://www.meetup.com/ReactNYC/) about the\n`useTrafficLight` code above, but it was the \"before\" code and did not use a custom hook, and\n_certainly_ not `react-hooks-helper` because it was not out yet!\n\nHere's my video.\n\n[![YouTube](https://user-images.githubusercontent.com/29359616/50539855-71bf5100-0b55-11e9-8c83-ac4b920fb5ea.png)](https://www.youtube.com/watch?v=mbiryVTIJ4Q\u0026t=3s)\n\n## License\n\n**[MIT](LICENSE)** Licensed\n\n## Code in the wild\n\nHave you built an app (real or sample) using `react-hooks-helper`? Make a PR and add it to the list below.\n\n- [Multi-step form demo](https://codesandbox.io/s/github/donavon/use-step-multi-step-form-demo)\n\n## Contributors\n\nThanks goes to these wonderful people ([emoji key](https://github.com/all-contributors/all-contributors#emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/revelcw\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/29359616?v=4\" width=\"100px;\" alt=\"Revel Carlberg West\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRevel Carlberg West\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#infra-revelcw\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=revelcw\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"#example-revelcw\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"#ideas-revelcw\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#maintenance-revelcw\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"#review-revelcw\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"#tool-revelcw\" title=\"Tools\"\u003e🔧\u003c/a\u003e \u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=revelcw\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://donavon.com\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/887639?v=4\" width=\"100px;\" alt=\"Donavon West\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDonavon West\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=donavon\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#ideas-donavon\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=donavon\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/threepointone\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/18808?v=4\" width=\"100px;\" alt=\"Sunil Pai\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSunil Pai\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=threepointone\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://bradastore.com\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/14840070?v=4\" width=\"100px;\" alt=\"Permadi Wibisono\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePermadi Wibisono\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=permadiwibisono\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://mmap.page\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/114114?v=4\" width=\"100px;\" alt=\"Jang Rush\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJang Rush\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/revelcw/react-hooks-helper/commits?author=weakish\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frevelcw%2Freact-hooks-helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frevelcw%2Freact-hooks-helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frevelcw%2Freact-hooks-helper/lists"}