{"id":18961006,"url":"https://github.com/itwin/react-hooks","last_synced_at":"2025-04-19T11:28:52.776Z","repository":{"id":38426307,"uuid":"329628687","full_name":"iTwin/react-hooks","owner":"iTwin","description":"common, generic, useful react hooks for general high-level react development","archived":false,"fork":false,"pushed_at":"2023-07-19T01:08:17.000Z","size":1001,"stargazers_count":5,"open_issues_count":6,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-08T15:04:50.940Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/iTwin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2021-01-14T13:48:23.000Z","updated_at":"2022-03-01T16:50:11.000Z","dependencies_parsed_at":"2024-10-29T14:22:59.042Z","dependency_job_id":null,"html_url":"https://github.com/iTwin/react-hooks","commit_stats":{"total_commits":65,"total_committers":6,"mean_commits":"10.833333333333334","dds":0.4,"last_synced_commit":"00e2fc8387bfd6e92c2b2a141a848468f6e5e7df"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iTwin%2Freact-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iTwin%2Freact-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iTwin%2Freact-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iTwin%2Freact-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iTwin","download_url":"https://codeload.github.com/iTwin/react-hooks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249195374,"owners_count":21228186,"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-11-08T14:11:00.394Z","updated_at":"2025-04-16T04:32:31.181Z","avatar_url":"https://github.com/iTwin.png","language":"TypeScript","readme":"# @bentley/react-hooks\n\n[![Build Status](https://dev.azure.com/bentleycs/iModelTechnologies/_apis/build/status/imodeljs.react-hooks)](https://dev.azure.com/bentleycs/iModelTechnologies/_build/latest?definitionId=4718)\n\nGeneric React hooks for daily development.\n\n## Hooks\n\n- **useAsyncEffect**: like `useEffect` but you can pass an async function and check if the component restarted the effect during your async operation.\n\n  ```tsx\n  useAsyncEffect(\n    async ({isStale, setCancel}) =\u003e {\n\n      const fetchPromise = fetch(`http://example.com/users/${userId}`);\n      // using setCancel, unfinished effect runs are cancelled by new runs\n      // this allows you to cancel requests you no longer need\n      setCancel(() =\u003e {\n        console.log(\"dependencies (userId) changed, cancelling old request!\")\n        // your async API must have some kind of cancellation\n        // for example, the fetch API can use an AbortController\n        fetchPromise.cancel();\n      })\n      const data = await fetchPromise;\n      if (!isStale())\n        setState(data);\n    },\n    [userId]\n  ).catch(err =\u003e {\n    console.log(\"an error occurred!\");\n    console.error(err);\n  });\n  ```\n- **useOnChange**: run an effect on a state change, but wait for some validity condition, any time you need to store a ref to previous state, consider this\n  ```tsx\n  const [activeType, setActiveType] = useState\u003cstring\u003e();\n  useOnChange(({prev}) =\u003e {\n    const [prevType] = prev;\n    uiToastNotifyUser(`active type changed from ${prevType} to ${activeType}`);\n  }, [activeType]);\n  ```\n  or wait for some third party non-react state, the effect reruns *every render* if the validity condition was not met, it only stops running once it's met and none\n  of the listened states have changed.\n  ```tsx\n  const viewport = thirdpartyLibrary.tryGetViewport();\n  const [userDefinedColor] = useState(\"red\");\n  useOnChange(() =\u003e {\n    // we know viewport is defined because of the condition\n    viewport!.setBackgroundColor(userDefinedColor);\n  }, viewport !== undefined, [userDefinedColor]);\n  ```\n- **useInterval**: the classic, run an effect every `n` milliseconds\n- **useAsyncInterval**: `useInterval` but with the same API for async effects as `useAsyncEffect`\n- **usePropertySetter**: for when you have an object in state but want a setter of its subproperty. Supports thunks (`prev=\u003enext` callbacks)\n    e.g.:\n    ```tsx\n    const [myobj, setMyobj] = useState({time: 5, area: \"world\"});\n    const setArea = usePropertySetter(\"area\", setMyobj);\n    useEffect(() =\u003e {\n      setArea(prevArea =\u003e prevArea === \"world\" ? \"hello\" : \"world\");\n    }, []);\n    return \u003cMySubcomponent setArea={setArea} /\u003e;\n    ```\n- **useValidatedInput**: useState for strings that are parsed into some other type (i.e. parsing a number input).\n  By default parses numeric input, but you can supply your own parse function, meaning you could handle search languages, SI units, lists, anything.\n  Returns an optional parse failure reason.\n  ```tsx\n  const [value, input, setInput] = useValidatedInput(\"5\", {\n    // don't change the numeric parsing but validate that it's a positive number\n    validate: (n: number) =\u003e {\n      const valid = /\\d+/.test(n);\n      return { valid, status: !valid ? \"only positive integers\" : undefined };\n    })\n  });\n  return \u003cinput value={input} onChange={e =\u003e setInput(e.currentTarget.value)} /\u003e;\n  ```\n- **useMediaQuery**: react to a media query (e.g. screen size \u003e 400px?)\n- **useScrolling**: react if your component is currently being scrolled through\n- **useHelp**: manage a contextual help link based on what components are currently rendering.\n  Internally this has been used to link to articles in a Bentley Communities page, based on which pages and menus (their components) are open (mounted).\n- **useInlineComponent**: for tiny components\n- **useOnMount**: for directly saying you're doing something is first added to the dom\n- **useOnUnmount**: for directly saying you're doing something when the component is removed from the dom\n- **useOnExternalClick**: A callback to fire on external clicks. Great for closing popups\n  ```tsx\n  const [isOpen, setIsOpen] = useState(true);\n  const popupElemRef = useRef\u003cHTMLDivElement\u003e(null);\n  useOnExternalClick(popupElemRef, () =\u003e setIsOpen(false)) // close popup if user clicks outside of it\n  return (\n    \u003cdiv\u003e\n      \u003cToolbar /\u003e\n      {isOpen \u0026\u0026 \u003cdiv ref={popupElemRef}\u003e\u003cUserPopup /\u003e\u003c/div\u003e}\n    \u003c/div\u003e\n  );\n  ```\n\n## Tips\n\nTo get `eslint-plugin-react-hooks` to warn on bad dependencies for hooks like\n`useAsyncEffect`, see the eslint rule's [advanced configuration docs](https://www.npmjs.com/package/eslint-plugin-react-hooks#advanced-configuration).\nOlder versions of `eslint-plugin-react-hooks` may warn on passing an async argument, we have a PR in react's monorepo to fix that eslint rule, and we can maintain a trivial fork if this is a common issue, because not warning on missed effects almost always leads to bug.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitwin%2Freact-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitwin%2Freact-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitwin%2Freact-hooks/lists"}