Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useRevalidate and RevalidateLink #9

Merged
merged 2 commits into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,18 @@ export default function Child() {
}
```

### RevalidateLink

The RevalidateLink link components it's a simple wrapper of a Remix's Link, it receives the same props with the exception of the `to`, instead this component will render a Link to `.`.

Because of linking to `.`, when clicked, this will tell Remix to fetch again the loaders of the current routes, but instead of creating a new entry on the browser's history stack, it will replace the current one, basically, it will refresh the page, but only reloading the data.

If you don't have JS enabled, this will do a full page refresh instead, giving you the exact same behavior.

```tsx
<RevalidateLink className="refresh-btn-styles">Refresh</RevalidateLink>
```

### useHydrated

This lets you detect if your component is already hydrated. This means the JS for the element loaded client-side and React is running.
Expand All @@ -207,6 +219,32 @@ When doing SSR, the value of `isHydrated` will always be `false`. The first clie

After the first client-side render, future components rendered calling this hook will receive `true` as the value of `isHydrated`. This way, your server fallback UI will never be rendered on a route transition.

### useRevalidate

This Hook gives you a function you can call to trigger a revalidation of the loaders in the current routes.

The way this works is by navigating to `.` and adding `replace: true` to avoid creating a new entry on the history stack.

> Check #RevalidateLink for more information and a component version of this feature that works without JS.

This Hooks is mostly useful if you want to trigger the revalidation manually from an effect, examples of this are:

- Set an interval to trigger the revalidation
- Revalidate when the browser tab is focused again
- Revalidate when the user is online again

```ts
import { useRevalidate } from "remix-utils";

function useRevalidateOnInterval() {
let revalidate = useRevalidat();
useEffect(() => {
let interval = setInterval(revalidate, 5000);
return () => clearInterval(interval);
}, [revalidate]);
}
```

### useShouldHydrate

If you are building a Remix application where most routes are static, and you want to avoid loading client-side JS, you can use this hook, plus some conventions, to detect if one or more active routes needs JS and only render the Scripts component in that case.
Expand Down
2 changes: 2 additions & 0 deletions src/react.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from "./react/client-only";
export * from "./react/csrf";
export * from "./react/outlet";
export * from "./react/revalidate-link";
export * from "./react/use-hydrated";
export * from "./react/use-revalidate";
export * from "./react/use-should-hydrate";
17 changes: 17 additions & 0 deletions src/react/revalidate-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Link, LinkProps } from "remix";

/**
* Renders a link that will revalidate the current route.
*
* This works by rendering a Link to `.`, which will tell Remix to reload all
* the loaders of the current routes and replace the position on the history
* stack. The later is important to let users click Back and go to the previous
* page instead of the same page with old data.
*
* This component is useful if you want to let users refresh manuall the data.
*
* @param props The props of the link, without the `to` prop.
*/
export function RevalidateLink(props: Omit<LinkProps, "to">) {
return <Link to="." {...props} />;
}
23 changes: 23 additions & 0 deletions src/react/use-revalidate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useCallback } from "react";
import { useNavigate } from "react-router-dom";

/**
* Trigger a revalidation of the current routes loaders.
*
* This work by navigating to the current page, this make Remix run the loaders
* of the current page again.
*
* The hook sets `replace: true` to the navigation options in order to avoid
* adding new history entries, this will avoid a case when the user clicks on
* the back button and it remains on the same page instead of going to the real
* previous page.
* @example
* let revalidate = useRevalidate();
* return <button type="button" onClick={() => revalidate}>Reload</button>;
*/
export function useRevalidate() {
let navigate = useNavigate();
return useCallback(() => {
navigate(".", { replace: true });
}, [navigate]);
}