{"id":27719390,"url":"https://github.com/gfox1984/granular-hooks","last_synced_at":"2025-04-27T07:44:42.201Z","repository":{"id":43098641,"uuid":"453924733","full_name":"gfox1984/granular-hooks","owner":"gfox1984","description":"Good old React hooks, with added granularity","archived":false,"fork":false,"pushed_at":"2023-07-11T17:20:00.000Z","size":274,"stargazers_count":17,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-27T07:44:36.825Z","etag":null,"topics":["hooks","react","useeffect"],"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/gfox1984.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-31T08:10:51.000Z","updated_at":"2025-03-11T09:51:42.000Z","dependencies_parsed_at":"2024-06-19T05:32:09.430Z","dependency_job_id":"747e2dbf-07eb-4c30-8bdf-6f6f9f79c80f","html_url":"https://github.com/gfox1984/granular-hooks","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/gfox1984%2Fgranular-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfox1984%2Fgranular-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfox1984%2Fgranular-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfox1984%2Fgranular-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gfox1984","download_url":"https://codeload.github.com/gfox1984/granular-hooks/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251106450,"owners_count":21537168,"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","useeffect"],"created_at":"2025-04-27T07:44:41.566Z","updated_at":"2025-04-27T07:44:42.188Z","avatar_url":"https://github.com/gfox1984.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# granular-hooks\n\nThe [React hooks](https://reactjs.org/docs/hooks-intro.html) you know, with added granularity. You can [read more about this](https://medium.com/@gfox1984/a-more-granular-useeffect-9c8ca3d9f634) on Medium.\n\n## The problem\n\nWho hasn't been in the situation where s/he needs an effect to run\nonly when _some_ of its dependencies have changed? Take this code for instance:\n\n```typescript\nimport { useEffect } from \"react\";\n\nuseEffect(() =\u003e {\n  if (condition) console.log(\"condition is true! value is\", value);\n  else console.log(\"condition is false! value is\", value);\n}, [value, condition]);\n```\n\nHere, the effect prints to the console each time `value` or `condition` change. You cannot print to the console ONLY when `value` changes because `useEffect` wants that [all values used by the effect are passed in the array of dependencies](https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect).\n\n## The solution\n\nWith minimal effort, `useGranularEffect` allows you to splits the array of dependencies into two: primary dependencies and secondaries dependencies.\n\n`useGranularEffect` guarantees that:\n\n- the effect only runs when the primary dependencies change\n- the cleanup function (if any) only runs when the primary dependencies change\n- when the effect runs, both primary and secondary dependencies are up-to-date\n\nThe example above can now be changed to:\n\n```typescript\nimport { useGranularEffect } from \"granular-hooks\";\n\nuseGranularEffect(\n  () =\u003e {\n    if (condition) console.log(\"condition is true! value is\", value);\n    else console.log(\"condition is false! value is\", value);\n  },\n  [value],\n  [condition]\n);\n```\n\nNow the code only prints to the console when `value` changes.\n\n## Installation\n\n```\nnpm install granular-hooks\n```\n\nor\n\n```\nyarn add granular-hooks\n```\n\n## Usage\n\n```typescript\nimport { useGranularEffect } from \"granular-hooks\";\n\nuseGranularEffect(\n  () =\u003e {\n    // the effect function, use your dependencies here\n    // dep1, dep2, dep3, dep4,...\n\n    // (optional) return a cleanup function\n    return () =\u003e {\n      /* cleanup*/\n    };\n  },\n  [dep1, dep2], // primary dependencies (runs when they change)\n  [dep3, dep4] // secondary dependencies (does not run when they change)\n);\n```\n\nThe only difference with `useEffect` is that the array of dependencies is split into two (the primary dependencies and the secondary dependencies). In fact, `useGranularEffect` uses `useEffect` under the hood, thus the similarities.\n\nSee the [React documentation for `useEffect`](https://reactjs.org/docs/hooks-reference.html#useeffect) for more information regarding the effect function, the optional cleanup function and dependencies.\n\nAlso check the general [rules of hooks](https://reactjs.org/docs/hooks-rules.html).\n\n## Other hooks\n\n`granular-hooks` also supports the following hooks:\n\n- `useGranularLayoutEffect`, based on [useLayoutEffect](https://reactjs.org/docs/hooks-reference.html#uselayouteffect)\n- `useGranularMemo`, based on [useMemo](https://reactjs.org/docs/hooks-reference.html#usememo)\n- `useGranularCallback`, based on [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)\n\nThe hooks have the same signature as their React equivalents, except that the array of dependencies is split into two, just like with `useGranularEffect`.\n\n## What's next?\n\nBelow are the features we're working on:\n\n- [x] Why stop with granular effect? granular memos and callback are calling too! Stay tuned.\n- [ ] What if we could also use a custom dependency comparer (other than the default `Object.is`)?\n- [ ] React hooks have a great [ESLint plugin](https://reactjs.org/docs/hooks-rules.html#eslint-plugin) that makes sure you don't forget to list dependencies when calling them. `granular-hooks` are still missing such tools.\n\n## FAQ\n\n### Can I leave the primary array of dependencies empty?\n\nYou can. That means that the effect will only run once, when the component is mounted (the initial render).\n\n### Can I leave the secondary array of dependencies empty?\n\nYou could but that would defeat the purpose of the hook. You might as well call `useEffect` directly.\n\n### Why use `useGranularEffect` when I can just omit some dependencies in `useEffect`?\n\nWhile you could technically do so, it would violate the rules exposed in [conditionally firing an effect](https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect):\n\n\u003e make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect. Otherwise, your code will reference stale values from previous renders.\n\nHaving said that, it should still work as intended (see [Understanding dependencies in useEffect](https://medium.com/@gfox1984/understanding-dependencies-in-useeffect-7afd4df37c96)). `useGranularEffect` will however help you be explicit about your dependencies and it will make sure that the effect is called with an exhaustive list of dependencies, even though this is not stricly necessary _technically speaking_.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgfox1984%2Fgranular-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgfox1984%2Fgranular-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgfox1984%2Fgranular-hooks/lists"}