Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/traviswimer/react-hydration-provider
react-hydration-provider makes it easy to control what your app renders before and after app hydration.
https://github.com/traviswimer/react-hydration-provider
Last synced: about 2 months ago
JSON representation
react-hydration-provider makes it easy to control what your app renders before and after app hydration.
- Host: GitHub
- URL: https://github.com/traviswimer/react-hydration-provider
- Owner: traviswimer
- License: mit
- Created: 2022-07-15T11:09:19.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-11-15T14:36:15.000Z (about 1 year ago)
- Last Synced: 2024-09-19T15:48:37.594Z (3 months ago)
- Language: TypeScript
- Homepage:
- Size: 188 KB
- Stars: 43
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
> `react-hydration-provider` makes it easy to control what your app renders before and after app hydration.
>
> This makes it simple to avoid hydration errors and other problems related to Server-side Rendering (SSR), Static Site Generation (SSG), Deferred Static Generation (DSG), etc.- [Learn about the problems this solves.](#problem-explanation)
- [View Examples](#examples)
- [Read the API reference](#api)
- Blog post about React hydration issues## Getting Started
### Install
**Yarn:**
```shell
yarn add react-hydration-provider
```**NPM:**
```shell
npm install react-hydration-provider
```### importing the package
**ES import**
```javascript
import {
HydrationContext,
HydrationProvider,
useHydrated,
Server,
Client,
createHydration,
useComponentHydrated,
} from "react-hydration-provider";
```**CommonJS require()**
```javascript
const {
HydrationContext,
HydrationProvider,
useHydrated,
Server,
Client,
createHydration,
useComponentHydrated,
} = require("react-hydration-provider");
```### Usage with Server Components
_Requires `react-hydration-provider` version 2.1.0 or later_
If you are using [React Server Components](https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components), you should be able to use `HydrationProvider` and it's corresponding hooks/components without any changes.
If you are using the standalone `useComponentHydrated` hook, you will need to include the [`"use client";`](https://react.dev/reference/react/use-client) directive in any component that uses it.
Usage examples
**Basic Example**
```javascript
import { HydrationProvider, Server, Client } from "react-hydration-provider";function App() {
return (
// HydrationProvider should usually be placed at a high level in your app.
This will be rendered during html generation (SSR, SSG, etc) and the
initial app hydration. It should always have a reliable value that
will render the same in both a server and client environment.
This will be rendered after initial app hydration.
It can safely contain dynamic content, like this: {Math.random()}
This will always be rendered.
);
}
```**Only render on client**
```javascript
import { HydrationProvider, Server, Client } from "react-hydration-provider";function App() {
return (
Nothing will be rendered to the user until the React app has
initialized and hydrated.
);
}
```**Manually checking hydration state**
```javascript
import { HydrationProvider, useHydrated } from "react-hydration-provider";function MyComponent() {
// useHydrated() is the same hook used by the and components.
// If and don't meet your needs, this can be used instead.
const hydrated = useHydrated();
return hydrated ?Client render
:Server render
;
}function App() {
return (
);
}
```**Skip the Provider**
`useComponentHydrated()` will cause a component to independently determine if the app is hydrated and may be less efficient.
Usually you will want to use `` and `` components. Using the provider allows the hydration check to only be performed once for your entire app.
[Read more about why you should use `useHydrated()` instead.](#hydration-rerenders-explanation)
```javascript
import { useComponentHydrated } from "react-hydration-provider";function MyComponent() {
const hydrated = useComponentHydrated();
return hydrated ?Client render
:Server render
;
}function App() {
return (
);
}
```API Reference
### ``
A Context Provider that allows child components to determine if the app has been hydrated.
This should generally be used near the highest level of your app.
_The only prop accepted is `children`_
### ``
Component to wrap the content you want to render when HTML is generated on a server or your local machine (SSR, SSG, DSG, etc). This content will also be rendered during the first render of your app to ensure your app matches the HTML during hydration.
**IMPORTANT: Ensure child components of `` are always predictable. It should always render the same. If not, you may still see hydration errors.**
### ``
Component to wrap the content you want to render after your React app has hydrated. It should never be rendered on the server-side.
Inside this component child components do not need to be reliable. It can render differently every time and there will be no hydration issues.
### `useHydrated()`
**React hook function**
Returns `true` if app is hydrated. Returns `false` if it has not yet been hydrated.
### `HydrationContext`
The React `Context` used by `HydrationProvider`.
You probably don't need to use this, but it is available in case there is an edge-case that requires it.
### `useComponentHydrated()`
**React hook function**
You should usually use `useHydrated()` instead.
It works exactly the same as `useHydrated()`, except the component using it will independently perform the hydration check each time it is mounted. This may [lead to inefficiencies](#hydration-rerenders-explanation).
This hook can be used completely independently. It does not require the use of a `HydrationProvider`.
### `createHydration()`
**Factory function to allow the use of multiple providers**
This function returns the same API as documented here (with the exception of `useComponentHydrated()` and `createHydration`):
- HydrationContext
- HydrationProvider
- Server
- Client
- useHydrated()This should only be necessary in complex scenarios where multiple Providers/Contexts are necessary.
_Example:_
```javascript
const { HydrationContext, HydrationProvider, useHydrated, Server, Client } =
createHydration();
```What problems does this solve?
Hydration Errors from client/server mismatch
Server-Side Rendering (SSR) and other pre-rendering methods require your client-side React app to use a process called "hydration" to seamlessly transition the HTML received from the server into an interactive Single-Page App (SPA).
For this to work correctly, the HTML from the server needs to **exactly** match what is generated by your React app or you will see errors/warnings:
- `Warning: Text content did not match. Server: "Pre-rendered server content" Client: "Client app content" at div.`
- `Warning: An error occurred during hydration. The server HTML was replaced with client content in div.`
- `Text content does not match server-rendered HTML.`
- `Hydration failed because the initial UI does not match what was rendered on the server.`
- `There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.`This is generally a result of your React app using dynamic content. For example, you might be using dates formatted to the current user's locale or you might be retrieving data from `localStorage`.
In these cases, your app requires data that is only available on the user's machine. Obviously the server (or your local machine) has no way of knowing what this data will be.
`react-hydration-provider` solves this using the `` and `` components. Putting all your dynamic content (Dates, localStorage, etc.) inside a `` ensures that it is not included during "hydration". If you want some content to be displayed only before the app has hydrated, you simply put it inside a ``. It is still possible to encounter mismatch errors from the content inside a ``. Ensure that it is always static/predictable on both the client and server.
Only one re-render
As the name implies, `react-hydration-provider` utilizes a React Context Provider (`HydrationProvider`) to store the hydration state of your React app.
The purpose of this is to only require the hydration check to run once at the highest level and then pass that down to `` and `` components.
The common way to check if an app is hydrated is to use `useEffect()` to delay certain code until after the first render. This is the technique used in `useComponentHydrated()`:
```javascript
export function useComponentHydrated() {
// Once useEffect() has been called, we know the app has been hydrated.
const [hydrated, setHydrated] = React.useState(false);
React.useEffect(() => {
setHydrated(true);
}, []);return hydrated;
}
```When you use this hook, it will trigger a re-render in the component that uses it when the value of `hydrated` changes.
Imagine you have a site with 2 pages, `page-a` and `page-b`. If a user directly navigates to the URL for `page-a`, your server will send them the HTML for `page-a`. Then your React app will hydrate and any components in `page-a` using `useComponentHydrated()` will re-render.
At this point everything is great, but now let's say the user clicks a link to navigate to `page-b`. Any components in `page-b` using `useComponentHydrated()` will render twice. This is completely unnecessary, as hydration mismatches are only a concern when the app first initializes.
By using a ``, ``, and ``, `react-hydration-provider` is able to run this check only once when the React app first initializes, eliminating the need for components to constantly re-render.
Basically, anything inside a `` will never be rendered if the app has already hydrated.
### SEO with dynamic content
One of the benefits of pre-rendering your HTML is that it makes it easier for search engines to crawl your site, since it isn't dependent on your React app initializing.
As explained in the [previous section](#hydration-errors-explanation), dynamic content causes hydration errors. A common solution is to simply delay rendering this content until after hydration. That means the HTML file will not contain this content, eliminating the SEO benefits.
In these cases, you can use the `` component to specify static content that should be included in the HTML file, allowing search engines to see this content before your React app has initialized.
### Displaying placeholders before app initialization
The `` component makes it simple to include placeholders like loading-spinners to improve your site's UX before the React app has initialized.
## Project Links
- [NPM](https://www.npmjs.com/package/react-hydration-provider)
- [GitHub](https://github.com/traviswimer/react-hydration-provider)## Author
#### Travis Wimer
- Developer Portfolio
- Blog
- react-hydration-provider Portfolio Page## License
MIT. Copyright © 2022 Travis Wimer