{"id":30667078,"url":"https://github.com/henriqueinonhe/use-debug-concurrent","last_synced_at":"2026-06-19T18:32:07.718Z","repository":{"id":192269006,"uuid":"686738884","full_name":"henriqueinonhe/use-debug-concurrent","owner":"henriqueinonhe","description":"A hook to debug React concurrent features. Attach callbacks to high and low priority renders.","archived":false,"fork":false,"pushed_at":"2023-09-03T20:24:52.000Z","size":23,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-30T11:38:44.128Z","etag":null,"topics":["concurrent","concurrent-mode","debug","hook","react","usedeferredvalue","usetransition"],"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/henriqueinonhe.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}},"created_at":"2023-09-03T19:27:47.000Z","updated_at":"2023-09-03T20:26:45.000Z","dependencies_parsed_at":"2023-09-03T21:59:51.763Z","dependency_job_id":null,"html_url":"https://github.com/henriqueinonhe/use-debug-concurrent","commit_stats":null,"previous_names":["henriqueinonhe/use-debug-concurrent"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/henriqueinonhe/use-debug-concurrent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriqueinonhe%2Fuse-debug-concurrent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriqueinonhe%2Fuse-debug-concurrent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriqueinonhe%2Fuse-debug-concurrent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriqueinonhe%2Fuse-debug-concurrent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/henriqueinonhe","download_url":"https://codeload.github.com/henriqueinonhe/use-debug-concurrent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriqueinonhe%2Fuse-debug-concurrent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273033887,"owners_count":25034277,"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","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["concurrent","concurrent-mode","debug","hook","react","usedeferredvalue","usetransition"],"created_at":"2025-08-31T22:21:34.083Z","updated_at":"2026-06-19T18:32:02.676Z","avatar_url":"https://github.com/henriqueinonhe.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Use Debug Concurrent\n\nA hook that helps you debug React concurrent features like `useTransition` a `useDeferredValue` by _hooking into_ (no pun intended) concurrent rendering lifecycles, i.e. high priority and low priority render phases.\n\nDebugging components that use concurrent rendering is tricky because they render (at least) twice, once due to the high priority update and another due to the low priority one and they may render even more times before comitting if low priority renders are interrupted.\n\nThis can make things very confusing when we want to inspect (e.g. log to console) values during render, especially because some values will differ between high and low priority renders.\n\nWith this hook, you can pass callbacks that will only run in a specific render phase, so you can easily inspect values and debug your components.\n\nIf you want to dive deeper into concurrent rendering or how this hook works, check [this article](https://blog.codeminer42.com/everything-you-need-to-know-about-concurrent-react-with-a-little-bit-of-suspense/#debugging-concurrent-rendering).\n\nYou can check a live demo here: https://stackblitz.com/edit/react-wzwn93\n\n## Installation\n\n```sh\nnpm install use-debug-concurrent\n```\n\nTypes are already included.\n\n## Usage\n\n```jsx\nimport { useDebugConcurrent } from \"use-debug-concurrent\";\n\nexport default function App() {\n  // This state will be updated by\n  // HIGH priority updates\n  const [filter, setFilter] = useState(\"\");\n  // This state will be updated by\n  // LOW priority updates\n  const [delayedFilter, setDelayedFilter] = useState(\"\");\n  const [isPending, startTransition] = useTransition();\n\n  useDebugConcurrent({\n    onFirstRenderStart: () =\u003e console.log(\"First render started\"),\n    onFirstRenderEnd: () =\u003e console.log(\"First render ended\"),\n    onHighPriorityStart: () =\u003e console.log(\"High priority render started\"),\n    onHighPriorityEnd: () =\u003e console.log(\"High priority render ended\"),\n    onLowPriorityStart: () =\u003e console.log(\"Low priority render started\"),\n    onLowPriorityEnd: () =\u003e console.log(\"Low priority render ended\"),\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        value={filter}\n        onChange={(e) =\u003e {\n          setFilter(e.target.value);\n          startTransition(() =\u003e {\n            // Here we're triggering the low\n            // priority update that will\n            // change `delayedFilter`'s value\n            setDelayedFilter(e.target.value);\n          });\n        }}\n      /\u003e\n\n      \u003cList filter={delayedFilter} /\u003e\n    \u003c/div\u003e\n  );\n}\n\nconst List = memo(({ filter }) =\u003e {\n  const filteredList = list.filter((entry) =\u003e\n    entry.name.toLowerCase().includes(filter.toLowerCase()),\n  );\n\n  return (\n    \u003cul\u003e\n      {filteredList.map((item) =\u003e (\n        \u003cli key={item.id}\u003e\n          {item.name} - ${item.price}\n        \u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  );\n});\n```\n\n## Caveats\n\n### First renders are ambiguous in terms of priority\n\nWhen the component renders for the first time, we cannot know whether that render is a high priority or low priority render just by looking at the component itself, we would need to understand what **triggered** the render in the first place, which comes from higher up in the component tree.\n\nFor instance, a component could be conditionally rendered by a parent component, and that parent component could be re-rendered by either a high priority or low priority update, which would make the child component's first render have the same priority as the parent's.\n\nThis is why we have two callbacks for first renders, `onFirstRenderStart` and `onFirstRenderEnd`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenriqueinonhe%2Fuse-debug-concurrent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenriqueinonhe%2Fuse-debug-concurrent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenriqueinonhe%2Fuse-debug-concurrent/lists"}