{"id":13429545,"url":"https://github.com/kitze/react-hanger","last_synced_at":"2025-05-14T14:08:09.345Z","repository":{"id":33199897,"uuid":"154839298","full_name":"kitze/react-hanger","owner":"kitze","description":"A collection of useful React hooks ","archived":false,"fork":false,"pushed_at":"2023-05-25T15:08:31.000Z","size":1895,"stargazers_count":1933,"open_issues_count":9,"forks_count":75,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-05-12T19:16:08.083Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://codesandbox.io/s/44m70xm70","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/kitze.png","metadata":{"files":{"readme":"README-ARRAY.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-26T13:31:15.000Z","updated_at":"2025-05-05T05:40:24.000Z","dependencies_parsed_at":"2024-06-18T12:39:35.563Z","dependency_job_id":"ae793f9a-7ef9-46b0-b5f1-1bea5ec86b63","html_url":"https://github.com/kitze/react-hanger","commit_stats":{"total_commits":134,"total_committers":24,"mean_commits":5.583333333333333,"dds":0.7537313432835822,"last_synced_commit":"76cce36d9422bc43773ab4705882b71e99e02bd8"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitze%2Freact-hanger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitze%2Freact-hanger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitze%2Freact-hanger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kitze%2Freact-hanger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kitze","download_url":"https://codeload.github.com/kitze/react-hanger/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159689,"owners_count":22024564,"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":[],"created_at":"2024-07-31T02:00:41.532Z","updated_at":"2025-05-14T14:08:09.325Z","avatar_url":"https://github.com/kitze.png","language":"TypeScript","funding_links":[],"categories":["Packages","TypeScript","Extensions/Libraries"],"sub_categories":[],"readme":"## API Reference (array destructuring)\r\n\r\n### How to import?\r\n\r\n```\r\nimport { useBoolean } from 'react-hanger/array' // will import all of functions\r\nimport useBoolean from 'react-hanger/array/useBoolean' // will import only this function\r\n```\r\n\r\n### useBoolean\r\n\r\n```jsx\r\nconst [showCounter, actions] = useBoolean(true);\r\n```\r\n\r\nActions:\r\n\r\n- `toggle`\r\n- `setTrue`\r\n- `setFalse`\r\n\r\n### useNumber\r\n\r\n```jsx\r\nconst [counter] = useNumber(0);\r\nconst [limitedNumber] = useNumber(3, { upperLimit: 5, lowerLimit: 3 });\r\nconst [rotatingNumber] = useNumber(0, {\r\n  upperLimit: 5,\r\n  lowerLimit: 0,\r\n  loop: true\r\n});\r\n```\r\n\r\nActions:\r\n\r\nBoth `increase` and `decrease` take an optional `amount` argument which is 1 by default, and will override the `step` property if it's used in the options.\r\n\r\n- `increase(amount = 1)`\r\n- `decrease(amount = 1 )`\r\n\r\nOptions:\r\n\r\n- `lowerLimit`\r\n- `upperLimit`\r\n- `loop`\r\n- `step` - sets the increase/decrease amount of the number upfront, but it can still be overriden by `number.increase(3)` or `number.decrease(5)`\r\n\r\n### useInput\r\n\r\nThis one is unique, since it returns tuple as a first element, where first element is `value` and second is `hasValue`\r\nSecond element is `actions` as usual\r\n\r\n```typescript\r\ntype UseInputActions = {\r\n  setValue: React.Dispatch\u003cSetStateAction\u003cstring\u003e\u003e;\r\n  onChange: (e: React.SyntheticEvent) =\u003e void\r\n  clear: () =\u003e void\r\n}\r\ntype UseInput = [[string, boolean], UseInputActions]\r\n```\r\n\r\n```jsx\r\nconst [[newTodo], actions] = useInput(\"\");\r\n```\r\n\r\n```jsx\r\n\u003cinput value={newTodo} onChange={actions.onChange} /\u003e\r\n```\r\nUseSetActions:\r\n\r\n- `clear`\r\n- `onChange` - default native event.target.value handler\r\n\r\nProperties:\r\n\r\n- `hasValue` -\r\n\r\n### useBindToInput\r\n\r\nDesigned to be used in composition with `useInput`.\r\nFirst and second elements are the same as `useInput.\r\nThird are bindings to spread.\r\n\r\n```jsx\r\nconst [[newTodo], actions, { nativeBind, valueBind }] = useBindToInput(useInput(\"\"));\r\n```\r\n\r\n```jsx\r\n\u003cinput value={newTodo} onChange={actions.onChange} /\u003e\r\n\u003cinput {...nativeBind} /\u003e\r\n\u003cSlider {...valueBind} /\u003e\r\n```\r\n\r\nUseSetActions:\r\n\r\n- `nativeBind` - binds the `value` and `onChange` props to an input that has `e.target.value`\r\n- `valueBind` - binds the `value` and `onChange` props to an input that's using only `value` in `onChange` (like most external components)\r\n\r\n### useArray\r\n\r\n```jsx\r\nconst [todos, actions] = useArray([]);\r\n```\r\n\r\nUseSetActions:\r\n\r\n- `push`\r\n- `unshift`\r\n- `pop`\r\n- `shift`\r\n- `clear`\r\n- `removeIndex`\r\n- `removeById` - if array consists of objects with some specific `id` that you pass\r\nall of them will be removed\r\n- `modifyById` - if array consists of objects with some specific `id` that you pass\r\nthese elements will be modified.\r\n- `move` - moves item from position to position shifting other elements. \r\n```\r\n    So if input is [1, 2, 3, 4, 5]\r\n    \r\n    from  | to    | expected\r\n    3     | 0     | [4, 1, 2, 3, 5]\r\n    -1    | 0     | [5, 1, 2, 3, 4]\r\n    1     | -2    | [1, 3, 4, 2, 5]\r\n    -3    | -4    | [1, 3, 2, 4, 5]\r\n```\r\n\r\n### useMap\r\n\r\n```jsx\r\nconst [someMap, someMapActions] = useMap([[\"key\", \"value\"]]);\r\nconst [anotherMap, anotherMapActions] = useMap(new Map([[\"key\", \"value\"]]));\r\n```\r\n\r\nActions:\r\n\r\n- `set`\r\n- `delete`\r\n- `clear`\r\n- `initialize` - applies tuples or map instances\r\n- `setValue`\r\n\r\n### useSet\r\n\r\n```jsx\r\nconst [ value, actions ] = useSet(new Set\u003cnumber\u003e([1, 2]))\r\n```\r\n\r\n`value` - a Set with only non mutating methods of a plain JS Set\r\n\r\nActions:\r\n\r\n- `setValue`\r\n- `add`\r\n- `remove`\r\n- `clear`\r\n\r\n## useSetState\r\n\r\n```jsx\r\nconst [state, setState, resetState] = useSetState({ loading: false });\r\nsetState({ loading: true, data: [1, 2, 3] });\r\n```\r\n\r\nActions:\r\n\r\n- `setState(value)` - will merge the `value` with the current `state` (like this.setState works in React)\r\n- `resetState()` - will reset the current `state` to the `value` which you pass to the `useSetState` hook\r\n\r\nProperties:\r\n\r\n- `state` - the current state\r\n\r\n## usePrevious\r\n\r\nUse it to get the previous value of a prop or a state value.  \r\nIt's from the official [React Docs](https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state).  \r\nIt might come out of the box in the future.\r\n\r\n```jsx\r\nconst Counter = () =\u003e {\r\n  const [count, setCount] = useState(0);\r\n  const prevCount = usePrevious(count);\r\n  return (\r\n    \u003ch1\u003e\r\n      Now: {count}, before: {prevCount}\r\n    \u003c/h1\u003e\r\n  );\r\n};\r\n```\r\n\r\n### Migration from object to array based\r\n\r\nAll value based hooks like `useBoolean`, `useNumber` etc. Are changed to \r\nbe using arrays, since it's more safe for reference equality, and also \r\nmakes it easier to use many `useSmth` without renaming `value` in destructuring.\r\n\r\nSo if you had \r\n```javascript\r\nconst { value: showHeader, ...showHeaderActions } = useBoolean(true)\r\nconst { value: showFooter, ...setShowFooterActions } = useBoolean(true)\r\n```\r\nIt will become\r\n```javascript\r\nconst [showHeader, showHeaderActions] = useBoolean(true)\r\nconst [showFooter, showFooterActions] = useBoolean(true)\r\n```\r\n\r\nNote that despite this code seems to be looking the same, it's not. Cause `showHeaderActions` in v1 will result\r\nin new object reference every rerender (because spreading creates new object, hence new reference). While in v2 actions are memoized \r\nusing `useMemo` and their reference will not change, cause they are not rely on value.\r\nIt enables us passing `actions` down the props without useless re-renders and excessive destructuring, it prevents `useEffects` and\r\nother hooks from re-run/new reference creation if autofix of ESLint rule `react-hooks/extraneous-deps` will add them as dependencies automatically.\r\n\r\n### useInput migration\r\nAlso big change to the `useInput`\r\nIf before you was not using `eventBind` and `nativeBind` from them, then using the same approach from above\r\nyou will get what you want. \r\nBut if you need bindings you need to compose `useInput` with `useBindToInput` like that:\r\nSo if you had\r\n```jsx\r\nconst { value, eventBind, valueBind, onChange, hasValue } = useInput(\"\")\r\n\r\n\u003cinput value={value} onChange={onChange} /\u003e\r\n\u003cinput {...eventBind} /\u003e\r\n{hasValue \u0026\u0026 \u003cSlider {...valueBind} /\u003e}\r\n```\r\nIt will become\r\n```jsx\r\nconst [[value, hasValue], actions, { eventBind, valueBind }] = useBindToInput(useInput(\"\"))\r\n\r\n\u003cinput value={value} onChange={actions.onChange} /\u003e\r\n\u003cinput {...eventBind} /\u003e\r\n{hasValue \u0026\u0026 \u003cSlider {...valueBind} /\u003e}\r\n```\r\n\r\nNote that first element in destructured array has tuple of `[value, hasValue]` since it's for values\r\nand second argument is for `actions` e.g. only for functions.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkitze%2Freact-hanger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkitze%2Freact-hanger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkitze%2Freact-hanger/lists"}