Skip to content

Instantly share code, notes, and snippets.

@mfunkie
Last active March 8, 2023 00:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfunkie/1c9cd6571dbb15d2328381469d218ba1 to your computer and use it in GitHub Desktop.
Save mfunkie/1c9cd6571dbb15d2328381469d218ba1 to your computer and use it in GitHub Desktop.
useRevalidateInterval
import { useEffect } from 'react';
import { useRevalidator, useSearchParams } from 'react-router-dom';
export function useRevalidateInterval(
shouldRevalidate: boolean,
revalidateSearchParam: string,
intervalTimeoutMs = 3000
) {
const [searchParams, setSearchParams] = useSearchParams();
const revalidator = useRevalidator();
const urlIndicatesRevalidate = Boolean(
searchParams.get(revalidateSearchParam)
);
useEffect(() => {
if (shouldRevalidate && !urlIndicatesRevalidate) {
setSearchParams((previousSearchParams) => {
// Preserve existing search parameters
const newSearchParams = new URLSearchParams(previousSearchParams);
newSearchParams.set(revalidateSearchParam, '1');
return newSearchParams;
});
} else if (!shouldRevalidate && urlIndicatesRevalidate) {
setSearchParams((previousSearchParams) => {
// Preserve existing search parameters
const newSearchParams = new URLSearchParams(previousSearchParams);
newSearchParams.delete(revalidateSearchParam);
return newSearchParams;
});
}
}, [
shouldRevalidate,
setSearchParams,
urlIndicatesRevalidate,
revalidateSearchParam
]);
useEffect(() => {
if (urlIndicatesRevalidate) {
// Trigger revalidator on an interval
// It is up to the implementer to use the same `urlSearchParameter`
// and if set, ensure a `network-only` fetchPolicy for any Apollo Queries
const intervalId = setInterval(() => {
// We may miss a tick in the interval but it is better
// than triggering revalidation while the query is still loading
if (revalidator.state !== 'loading') {
revalidator.revalidate();
}
}, intervalTimeoutMs);
return () => {
clearInterval(intervalId);
};
}
}, [revalidator, urlIndicatesRevalidate, intervalTimeoutMs]);
}
@mfunkie
Copy link
Author

mfunkie commented Mar 8, 2023

Summary

useRevalidateInterval is a hook intended for use with react-router-dom.

  • Set search param presence based on a condition.
  • Call revalidator.revalidate() on a specified interval based on the presence of revalidation search param.

The value of 1 for the search param value, the default interval, and comments about Apollo are arbitrary.

Use case

For lists of elements, I sometimes have a pending status while additional work is being done on an item on that list. This is typically not long-lived. My loaders query data from Apollo Client, and need to be informed of when to use network-only as a fetchPolicy. With this hook, I can check for the presence of a pending item in my loader resultant list data, pass to this hook, and be assured that the list will refresh until the item is no longer pending (presuming fetchPolicy implementation inside loader

@mfunkie
Copy link
Author

mfunkie commented Mar 8, 2023

Implementation in loader may look something like:

const url = new URL(request.url);
const shouldRefetch = Boolean(url.searchParams.get('myRevalidateSearchParam'));

const result = await client.query<Query, Variables>({
  query: LIST_QUERY,
  variables: { listId },
  fetchPolicy: shouldRefetch ? 'network-only' : 'cache-first'
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment