{"id":16427105,"url":"https://github.com/donavon/use-instance","last_synced_at":"2025-03-21T04:30:44.270Z","repository":{"id":34304127,"uuid":"175476671","full_name":"donavon/use-instance","owner":"donavon","description":"A custom React Hook that provides a sensible alternative to useRef for storing instance variables.","archived":false,"fork":false,"pushed_at":"2023-01-03T17:47:13.000Z","size":686,"stargazers_count":39,"open_issues_count":16,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-17T20:43:46.955Z","etag":null,"topics":["hooks","react","reactjs"],"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/donavon.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":"2019-03-13T18:25:02.000Z","updated_at":"2025-01-08T14:20:53.000Z","dependencies_parsed_at":"2023-01-15T06:15:17.140Z","dependency_job_id":null,"html_url":"https://github.com/donavon/use-instance","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donavon%2Fuse-instance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donavon%2Fuse-instance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donavon%2Fuse-instance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donavon%2Fuse-instance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/donavon","download_url":"https://codeload.github.com/donavon/use-instance/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244738186,"owners_count":20501791,"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":["hooks","react","reactjs"],"created_at":"2024-10-11T08:11:35.152Z","updated_at":"2025-03-21T04:30:43.990Z","avatar_url":"https://github.com/donavon.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @use-it/instance 🐘\n\nA custom React Hook that provides a sensible alternative to `useRef` for storing instance variables.\n\n[![npm version](https://badge.fury.io/js/%40use-it%2Finstance.svg)](https://badge.fury.io/js/%40use-it%2Finstance)\n[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors)\n\n## Why?\n\n`useRef` is weird. The official React docs say:\n\n\u003e `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument (`initialValue`). The returned object will persist for the full lifetime of the component.\n\n\u003e Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.\n\nThe fact that you have to access it via `.current` is strange.\nThe fact that the React docs call out that you can use it for more than\nref attributes is telling.\nThey have to know that `useRef` is confusing too.\n\nThat's why I created `useInstance`.\nYou treat the object returned by `useInstance` just like you would `this` in a class component,\nso you're already familiar with how it works.\n\nSo… Use `useRef` if you're dealing with actual DOM elements—use\n`useInstance` for instance properties and methods.\n\nSome may say _\"Six of one, hald dozen of another,\"_ and they could be right.\nBut if you're in the \"half-dozen\" camp, `useInstance` might well be for you!\n\nWant more evidence that `useRef` is weird?\nIn the latest [React v17 RC](https://reactjs.org/blog/2020/08/10/react-v17-rc.html#potential-issues) under \"Potential Issues\" it shows that this code could break.\n\n```js\nuseEffect(() =\u003e {\n  someRef.current.someSetupMethod();\n  return () =\u003e {\n    someRef.current.someCleanupMethod();\n  };\n});\n```\n\nThe solution that they are suggesting (below) is to use an instance variable, which is exactly what `useInstance` is doing. Had React implimented `useInstance` this \"potential issue\" would never have been raised.\n\n```js\nuseEffect(() =\u003e {\n  const instance = someRef.current;\n  instance.someSetupMethod();\n  return () =\u003e {\n    instance.someCleanupMethod();\n  };\n});\n```\n\n## Installation\n\n```bash\n$ npm i @use-it/instance\n```\n\nor\n\n```bash\n$ yarn add @use-it/instance\n```\n\n## Usage\n\nHere is a basic setup. Most people will name the returned object\n`self` or `that` or `instance`, but you can call it anything you'd like.\n\n```js\nimport useInstance from '@use-it/instance';\n\n// Then from within your function component\nconst instance = useInstance(initialInstance);\n```\n\n### Parameters\n\nHere are the parameters that you can use. (\\* = optional)\n\n| Parameter         | Description                                                                                                                        |\n| :---------------- | :--------------------------------------------------------------------------------------------------------------------------------- |\n| `initialInstance` | Is an object or a function that returns an object that represents the initial instance value. Defaults to an empty object literal. |\n\n### Return\n\nThe return value is an object that WILL NOT change on subsequent calls to your function component.\nUse it just like you would to create instance properties and methods in a class component.\n\n## Examples\n\n### A replacement for `useRef`\n\nHere's an example where you might use `useRef`.\nWithin the closure of the `useEffect`, if we simply reference\n`callback` directly, we will see `callback` as it was during the\ncreation of the function.\nInstead we must make it \"live\" throughout many render cycles.\n\n```js\nfunction useInterval(callback, delay) {\n  const savedCallback = useRef();\n  savedCallback.current = callback;\n\n  useEffect(() =\u003e {\n    function tick() {\n      savedCallback.current();\n    }\n    if (delay !== null) {\n      const id = setInterval(tick, delay);\n      return () =\u003e clearInterval(id);\n    }\n  }, [delay]);\n}\n```\n\nAnd here's the same code using `useInstance`.\nIt has a more familiar class component-like syntax.\nAgain, think of `instance` as `this`.\n\n```js\nfunction useInterval(callback, delay) {\n  const instance = useInstance();\n  instance.savedCallback = callback;\n\n  useEffect(() =\u003e {\n    function tick() {\n      instance.savedCallback();\n    }\n    if (delay !== null) {\n      const id = setInterval(tick, delay);\n      return () =\u003e clearInterval(id);\n    }\n  }, [delay]);\n}\n```\n\n### A replacement for `useCallback`/`useMemo`\n\nYou can also use `useInstance` in place of `useCallback` and `useMemo` for some cases.\n\nTake for instance (pardon the pun), this simple up/down counter example.\nYou might use `useCallback` to ensure that the pointers\nto the `increment` and `decrement` function didn't change.\n\n```js\nconst useCounter = initialCount =\u003e {\n  const [count, setCount] = useState(initialCount);\n  const increment = useCallback(() =\u003e setCount(c =\u003e c + 1));\n  const decrement = useCallback(() =\u003e setCount(c =\u003e c - 1));\n\n  return {\n    count,\n    increment,\n    decrement,\n  };\n};\n```\n\nOr, you could store them in the instance, much like you\nmight have done with a class component.\n\n```js\nconst useCounter = initialCount =\u003e {\n  const [count, setCount] = useState(initialCount);\n  const self = useInstance({\n    increment: () =\u003e setCount(c =\u003e c + 1),\n    decrement: () =\u003e setCount(c =\u003e c - 1),\n  });\n\n  return {\n    count,\n    ...self,\n  };\n};\n```\n\nWhat is the benefit of keeping functions in instances variable\ninstead of using `useCallback`?\nThis is from the official Hooks documentation.\n\n\u003e In the future, React may choose to “forget” some previously memoized values and recalculate them on next render.\n\nInstance variables never forget. 🐘\n\n### Lazy initialization\n\nIf computing the `initialInstance` is costly, you may pass a function that returns an `initialInstance`.\n`useInstance` will only call the function on mount.\n\nNot that creating two functions is expensive,\nbut we could re-write the example above using a lazy initializer, like this.\n\n```js\n// this is only called once, on mount, per component instance\nconst getInitialInstance = setCount =\u003e ({\n  increment: () =\u003e setCount(c =\u003e c + 1),\n  decrement: () =\u003e setCount(c =\u003e c - 1),\n});\n\nconst useCounter = initialCount =\u003e {\n  const [count, setCount] = useState(initialCount);\n  const self = useInstance(getInitialInstance(setCount));\n\n  return {\n    count,\n    ...self,\n  };\n};\n```\n\nNotice that we moved `getInitialInstance` into a static fucntion _outside_ of `useCounter`.\nThis helps to reduce the complexity of `useCounter`.\nAn added side effect is that `getInitialInstance` is now highly testable.\n\nYou might even take this one step further and refactor your methods\ninto it's own custom Hook. Isn't coding fun? 😊\n\n```js\nconst getInitialInstance = setCount =\u003e ({\n  increment: () =\u003e setCount(c =\u003e c + 1),\n  decrement: () =\u003e setCount(c =\u003e c - 1),\n});\n\nconst useCounterMethods = setCount =\u003e useInstance(getInitialInstance(setCount));\n\nconst useCounter = initialCount =\u003e {\n  const [count, setCount] = useState(initialCount);\n  const methods = useCounterMethods(setCount);\n\n  return {\n    count,\n    ...methods,\n  };\n};\n```\n\n## Live demo\n\nYou can view/edit the \"you clicked\" sample code above on CodeSandbox.\n\n[![Edit demo app on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/6wqqr4y9oz)\n\n## License\n\n**[MIT](LICENSE)** Licensed\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-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\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=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDonavon West\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-donavon\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#infra-donavon\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"#maintenance-donavon\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/donavon/use-instance/pulls?q=is%3Apr+reviewed-by%3Adonavon\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/donavon/use-instance/commits?author=donavon\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#design-donavon\" title=\"Design\"\u003e🎨\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/derek-rmd\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/46328094?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDerek Jones\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/donavon/use-instance/commits?author=derek-rmd\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-enable --\u003e\n\u003c!-- prettier-ignore-end --\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%2Fdonavon%2Fuse-instance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdonavon%2Fuse-instance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonavon%2Fuse-instance/lists"}