Skip to content

Commit

Permalink
Create ServerOnly component (#207)
Browse files Browse the repository at this point in the history
Closes #206
  • Loading branch information
sergiodxa committed Jun 9, 2023
1 parent 0e1ae22 commit f13e9f4
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,37 @@ The rendering flow will be:

This component uses the `useHydrated` hook internally.

### ServerOnly

The ServerOnly component is the opposite of the ClientOnly component, it lets you render the children element only on the server-side, avoiding rendering it the client-side.

You can provide a fallback component to be used on CSR, and while optional, it's highly recommended to provide one to avoid content layout shift issues, unless you only render visually hidden elements.

```tsx
import { ServerOnly } from "remix-utils";

export default function Component() {
return (
<ServerOnly fallback={<ComplexComponentNeedingBrowserEnvironment />}>
{() => <SimplerStaticVersion />}
</ServerOnly>
);
}
```

This component is handy to render some content only on the server-side, like a hidden input you can later use to know if JS has loaded.

Consider it like the `<noscript>` HTML tag but it can work even if JS failed to load but it's enabled on the browser.

The rendering flow will be:

- SSR: Always render the children.
- CSR First Render: Always render the children.
- CSR Update: Update to render the fallback component (if defined).
- CSR Future Renders: Always render the fallback component, don't bother to render the children.

This component uses the `useHydrated` hook internally.

### CORS

The CORS function let you implement CORS headers on your loaders and actions so you can use them as an API for other client-side applications.
Expand Down
29 changes: 29 additions & 0 deletions src/react/server-only.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ReactNode } from "react";
import { useHydrated } from "./use-hydrated";

type Props = {
/**
* You are encouraged to add a fallback that is the same dimensions
* as the server rendered children. This will avoid content layout
* shift which is disgusting
*/
children(): ReactNode;
fallback?: ReactNode;
};

/**
* Render the children only before the JS has loaded client-side. Use an
* optional fallback component for once the JS has loaded.
*
* Example: Render a hidden input to identify if the user has JS.
* ```tsx
* return (
* <ServerOnly fallback={<FakeChart />}>
* {() => <Chart />}
* </ServerOnly>
* );
* ```
*/
export function ServerOnly({ children, fallback = null }: Props) {
return useHydrated() ? <>{fallback}</> : <>{children()}</>;
}

0 comments on commit f13e9f4

Please sign in to comment.