Skip to content

Instantly share code, notes, and snippets.

@dctanner
Created June 29, 2023 12:34
Show Gist options
  • Save dctanner/882a71fbb6f15153108cdfdf5f33c545 to your computer and use it in GitHub Desktop.
Save dctanner/882a71fbb6f15153108cdfdf5f33c545 to your computer and use it in GitHub Desktop.
Reload loader data at interval without throwing error on network failure
import useRegularFetchWithInterval from "./useRegularFetchWithInterval";
export async function loader() {
// Get data
return data;
}
export default function MyRoute() {
const loaderData = useLoaderData();
const [liveData] = useRegularFetchWithInterval({ route: `/myroute?_data=routes%2Fmyroute`, intervalMs: 3000, initialData: loaderData });
return (
<>{liveData}</>
);
}
import { useEffect, useRef } from "react";
export default function useInterval(callback: () => void, delay: number) {
const savedCallback = useRef<any>();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
import { useState, useCallback } from "react";
import useInterval from "./useInterval";
// Do fetch() to the route at interval and return a state object of the latest value
export default function useRegularFetchWithInterval({ route, intervalMs, enabled = true, skipInitialFetch = false, initialData }: { route: string; intervalMs: number; enabled?: boolean | (() => boolean); skipInitialFetch?: boolean; initialData?: any }) {
const [data, setData] = useState<any>(initialData);
const [error, setError] = useState<any>(null);
const options = {
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
const fetchData = useCallback(() => {
// If enabled is a function, call it to determine if we should fetch, or if it's a boolean just use it
if (typeof enabled === "function" && !enabled()) return;
if (typeof enabled === "boolean" && !enabled) return;
fetch(route, options)
.then((res) => res.json())
.then((data) => setData(data))
.catch((err) => setError(err));
}, [route, enabled]);
useInterval(fetchData, intervalMs);
return [data, error, fetchData];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment