{"id":16720321,"url":"https://github.com/tomokimiyauci/react-partial-hydration","last_synced_at":"2026-03-07T06:02:24.671Z","repository":{"id":37786808,"uuid":"408108360","full_name":"TomokiMiyauci/react-partial-hydration","owner":"TomokiMiyauci","description":"React component for partial hydration","archived":false,"fork":false,"pushed_at":"2023-01-26T22:11:47.000Z","size":578,"stargazers_count":5,"open_issues_count":5,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-11-07T16:00:34.503Z","etag":null,"topics":["partial-hydration","progressive-hydration","react"],"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/TomokiMiyauci.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":"FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null},"funding":{"github":"TomokiMiyauci","patreon":"tomoki_miyauci"}},"created_at":"2021-09-19T11:27:11.000Z","updated_at":"2025-01-11T04:05:41.000Z","dependencies_parsed_at":"2023-02-15T01:46:48.703Z","dependency_job_id":null,"html_url":"https://github.com/TomokiMiyauci/react-partial-hydration","commit_stats":null,"previous_names":["tomokimiyauci/react-patial-hydration"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/TomokiMiyauci/react-partial-hydration","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Freact-partial-hydration","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Freact-partial-hydration/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Freact-partial-hydration/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Freact-partial-hydration/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TomokiMiyauci","download_url":"https://codeload.github.com/TomokiMiyauci/react-partial-hydration/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Freact-partial-hydration/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30208801,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T05:23:27.321Z","status":"ssl_error","status_checked_at":"2026-03-07T05:00:17.256Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["partial-hydration","progressive-hydration","react"],"created_at":"2024-10-12T22:06:37.280Z","updated_at":"2026-03-07T06:02:24.648Z","avatar_url":"https://github.com/TomokiMiyauci.png","language":"TypeScript","funding_links":["https://github.com/sponsors/TomokiMiyauci","https://patreon.com/tomoki_miyauci","https://www.patreon.com/tomoki_miyauci"],"categories":[],"sub_categories":[],"readme":"# react-partial-hydration\n\nReact component to delay or skip hydration.\n\nIt can be combined with lazy component to achieve the best performance. See [React.lazy](#Lazy-component) for details.\n\n## Quick view\n\n### Install\n\n```bash\nyarn add react-partial-hydration\n```\n\nor\n\n```bash\nnpm i react-partial-hydration\n```\n\n### Static\n\nThe `children` of the `Static` component will skip hydration.\n\n```tsx\nimport { Static, Intersection } from 'react-partial-hydration'\n;\u003cStatic\u003e{children}\u003c/Static\u003e\n```\n\n### Intersection\n\nThe `children` of the `Intersection` component will delay hydration until it intersects the viewport.\n\n```tsx\nimport { Intersection } from 'react-partial-hydration'\n;\u003cIntersection\u003e{children}\u003c/Intersection\u003e\n```\n\n## API\n\nThis provide components as below:\n\n- Static\n- Intersection\n\n### Static\n\nNo(skip) hydration component\n\nIf the component does not need to be reactive, it can be optimized for performance.\n\n```tsx\nimport { Static } from 'react-partial-hydration'\n;\u003cStatic\u003e{children}\u003c/Static\u003e\n```\n\n#### props\n\n| Prop         | Default    | Description                                                                                                         |\n| ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------- |\n| `children`   | -          | `JSX.Element`\u003cbr /\u003eThe children component                                                                           |\n| `as`         | `div`      | `keyof ReactHTML` ? \u003cbr /\u003e`Static` component should render as.                                                      |\n| `fallback`   | `children` | `false` \u0026#124; `JSX.Element` ? \u003cbr /\u003eWhen The DOM is not exists, fallback to `children` or passed component or not. |\n| `onFallback` | -          | `() =\u003e void` ? \u003cbr /\u003eOn fallback component is rendered, then fire                                                   |\n| `...props`   | -          | `DetailedHTMLProps\u003cHTMLAttributes\u003cHTMLElement\u003e, HTMLElement\u003e` ? \u003cbr /\u003eAll attributes to render `Static` component.  |\n\n#### SSR render\n\nBy default, on the server side, it will be rendered as follows:\n\n```html\n\u003cdiv style=\"display:contents\"\u003e{children}\u003c/div\u003e\n```\n\nThe only drawback now is that it requires a wrapper `HTML` tag.\nFortunately, `display:contents` does not break the style of `children`. Also, there will probably be no impact on SEO.\n\n#### CSR render\n\nOn the client side, skip hydration and keep the DOM tree.\n\n```html\n\u003cdiv style=\"display:contents\"\u003e{children}\u003c/div\u003e\n```\n\n### Intersection\n\nThe component to delay hydration until it intersects the viewport.\n\n```tsx\nimport { Intersection } from 'react-partial-hydration'\n;\u003cIntersection\u003e{children}\u003c/Intersection\u003e\n```\n\n#### props\n\n| Prop         | Default    | Description                                                                                                                                                                               |\n| ------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `children`   | -          | `JSX.Element`\u003cbr /\u003eThe children component.                                                                                                                                                |\n| `as`         | `div`      | `keyof ReactHTML` ? \u003cbr /\u003e`Intersection` component should render as.                                                                                                                      |\n| `fallback`   | `children` | `false` \u0026#124; `JSX.Element` ? \u003cbr /\u003eWhen The DOM is not exists, fallback to `children` or passed component or not.                                                                       |\n| `onFallback` | -          | `() =\u003e void` ? \u003cbr /\u003eOn fallback component is rendered, then fire.                                                                                                                        |\n| `target`     | `\u003cdiv /\u003e`  | `JSX.Element` ? \u003cbr /\u003eTarget used for intersection.                                                                                                                                       |\n| `root`       | -          | `Element` \u0026#124; `Document` \u0026#124; `null` ? \u003cbr /\u003eThe element that is used as the viewport for checking visibility of the target.                                                         |\n| `rootMargin` | -          | `string` ? \u003cbr /\u003eMargin around the root.                                                                                                                                                  |\n| `threshold`  | -          | `number` \u0026#124; `number[]` ? \u003cbr /\u003eEither a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed. |\n| `...props`   | -          | `DetailedHTMLProps\u003cHTMLAttributes\u003cHTMLElement\u003e, HTMLElement\u003e` ? \u003cbr /\u003eAll attributes to render `Intersection` component.                                                                  |\n\n#### SSR render\n\nBy default, on the server side, it will be rendered as follows:\n\n```html\n\u003cdiv style=\"display:contents\"\u003e\n  \u003cdiv /\u003e\n  {children}\n\u003c/div\u003e\n```\n\nThe only drawback now is that it requires a wrapper `HTML` tag.\nFortunately, `display:contents` does not break the style of `children`. Also, there will probably be no impact on SEO.\n\n#### CSR render\n\nOn the client side, hydration is delayed until Intersect.\n\n```html\n\u003cdiv style=\"display:contents\"\u003e\n  \u003cdiv /\u003e\n  {children}\n\u003c/div\u003e\n```\n\n### Architecture\n\nNormally, if a react component does not return any `DOM Elements`, it will be removed from the `DOM` or React will report an error.\n\nFor example, the following component will cause a flush and be removed from the DOM tree in browser.\n\n```tsx\nimport type { FC } from 'react'\nconst FlashThenRemove: FC = () =\u003e {\n  if (isServer) {\n    return \u003cdiv\u003eThis will delete from DOM\u003c/div\u003e\n  }\n  return \u003c\u003e\u003c/\u003e\n  // or return void\n}\n```\n\nSSR:\n\n```html\n\u003cdiv\u003eThis will delete from DOM\u003c/div\u003e\n```\n\nCSR:\n\n```html\n// Flash and disappear\n```\n\nIn order to maintain the DOM tree without using `hydrate` or `render`, we can use `dangerouslySetInnerHTML`.\n\n```tsx\nconst NoHydrate: FC = () =\u003e {\n  if (isServer) {\n    return \u003cdiv\u003eThis will not delete from DOM\u003c/div\u003e\n  }\n  return (\n    \u003cdiv\n      dangerouslySetInnerHTML={{\n        __html: ''\n      }}\n    /\u003e\n  )\n}\n```\n\nIt relies on the original `html`. On the server side and the client side, the parent component must be the same `HTML` tag.\n\nFor example, in the above example, if you change the `div` tag in the server-side generated `html` to a `span` tag, nothing will be rendered on the client side.\n\n### The fallback system\n\nFrom the above example, we can see that hydration skipping depends on the original `html`. If the `html` is not what you expect, it will disappear from the DOM tree. This can be a problem.\n\nThe best example of where this situation occurs is when you are using an [App Shell](https://developers.google.com/web/fundamentals/architecture/app-shell).\n\nApp Shell uses a `Service worker` to get assets from cache storage so that the app can work offline.\n\nIn this case, the original `html` DOM tree is empty unless you make your own changes, because App Shell is based on CSR.\n\nTo work correctly in this situation, all components have a fallback system implemented.\n\nThis means that if the correct DOM is not rendered, hydration will occur and the correct DOM will be corrected.\n\nThe `fallback` props allows you to specify which components to fallback. The default is `children`. You can disable fallback by setting it to `false`.\n\n## Lazy component\n\nBy using these components, hydration will be delayed or not occur. This will improve performance.\n\nHowever, the fetch of the component will still take place.\n\nLet's look at the following example.\n\n```tsx\nimport type { FC } from 'react'\ntype Props = {\n  title: string\n  description: string\n}\nconst Headline: FC\u003cProps\u003e = ({ title, description }) =\u003e {\n  return (\n    \u003carticle\u003e\n      \u003ch2\u003e{title}\u003c/h2\u003e\n      \u003cp\u003e{description}\u003c/p\u003e\n    \u003c/article\u003e\n  )\n}\nexport default Headline\n```\n\n```tsx\nimport Headline from 'path/to/headline'\nimport { Static } from 'react-partial-hydration'\n\n\u003cStatic\u003e\n  \u003cHeadline title=\"Hello\" description=\"World\"\u003e\n\u003c/Static\u003e\n```\n\nThe `Headline` component is not hydrated by the `Static` component. This is certainly a good thing for performance.\nHowever, since the `Headline` component is not chunked, it will be included in the main bundle.\n\nEven though it is not used for rendering, it increases the main bundle and the user is fetching unnecessary scripts.\n\nTo remedy this, we will use the lazy component.\n\n### React.lazy\n\nThe `React.lazy` function can create lazy components.\n\nThe lazy component is characterized by the fact that it will be fetched only when it is needed.\n\nFor example, let's look at the following example:\n\n```tsx\nimport { lazy, useState } from 'react'\n\nconst Headline = lazy(() =\u003e import('path/to/headline'))\n\nconst Main: FC = () =\u003e {\n  const [isShow, changeShow] = useState(false)\n\n  return isShow \u0026\u0026 \u003cHeadline title=\"Hello\" description=\"World\"\u003e\n}\n```\n\nFor the `Headline` component, the component fetch itself will be delayed until the `isShow` is `true`.\n\nUnfortunately, `React.lazy` doesn't support SSR yet.\n\n### Third-party lazy components\n\n[Loadable Components](https://loadable-components.com/) is the [officially](https://reactjs.org/docs/code-splitting.html#reactlazy) recommended Code Splitting library that supports SSR. By using it, you can render lazy components on the server side.\n\n\u003e There are no dependencies in this project. You can also use solutions other than `Loadable Components`.\n\nThe rendering of lazy components on the server side depends on the bundler.\n\nYou can see how to use Loadable Components on the server side in the following example.\n\n- Gatsby [WIP]\n- Next.js [WIP]\n\nOnce your application is ready, you can use it as follows:\n\n```tsx\nimport loadable from '@loadable/component'\nimport { Static } from 'react-partial-hydration'\nconst Headline = loadable(() =\u003e import('path/to/headline'))\n\n\u003cStatic\u003e\n  \u003cHeadline title=\"Hello\" description=\"World\"\u003e\n\u003c/Static\u003e\n```\n\nThis will cause the markup to be rendered on the server side.\nAnd on the client side, the **fetch** and **hydration** of the component will be skipped.\n\nSimilarly for the `Intersection` component, no **fetch** or **hydration** will be done until it is intersected.\n\n## Contributing\n\nContributions, issues and feature requests are welcome!\u003cbr /\u003eFeel free to check\n[issues](https://github.com/TomokiMiyauci/utterances-component/issues).\n\n## Show your support\n\nGive a ⭐️ if this project helped you!\n\n\u003ca href=\"https://www.patreon.com/tomoki_miyauci\"\u003e\n  \u003cimg src=\"https://c5.patreon.com/external/logo/become_a_patron_button@2x.png\" width=\"160\"\u003e\n\u003c/a\u003e\n\n## License\n\nCopyright © 2021-present [TomokiMiyauci](https://github.com/TomokiMiyauci).\n\nReleased under the [MIT](./LICENSE) license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomokimiyauci%2Freact-partial-hydration","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomokimiyauci%2Freact-partial-hydration","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomokimiyauci%2Freact-partial-hydration/lists"}