# Data Revalidation in Remix

By [Vanxh](https://paragraph.com/@vanxh) · 2023-02-17

---

Libraries like [SWR](https://swr.vercel.app/docs/getting-started) or [React Query](https://tanstack.com/query/v4) have automatic data revalidation built in, but what about [Remix](https://remix.run)?

Remix has a great built-in utility to fetch data (`loader` and `useLoaderData`). It automatically revalidates data on all actions.

Let’s see how you can add more ways to revalidate your data such as interval/focus based data revalidation:

### Create a loader to fetch your data

    type LoaderData= {
        user: User;
    };
    
    export const loader: LoaderFunction = async () => {
        const res = await fetch("/api/user/me");
        const data = await res.json();
    
        return json<LoaderData>({ user: data });
    };
    

This will make remix fetch the data whenever the route loads.

_Make sure loader is exported from the same file your route is in._

### Use the loader in your component

    export function User() {
        const { user } = useLoaderData<LoaderData>();
    
        return <p>{user.username}</p>;
    }
    

### Create a revalidate hook

`useRevalidate` can be use to trigger data refresh. It triggers a navigation event to the current route which triggers Remix to call loader of the route.

    import { useCallback } from "react";
    import { useNavigate } from "@remix-run/react";
    
    export const useRevalidate = () => {
      // We get the navigate function from React Rotuer
      let navigate = useNavigate();
      // And return a function which will navigate to `.` (same URL) and replace it
      return useCallback(
        function revalidate() {
          navigate(".", { replace: true });
        },
        [navigate]
      );
    };
    

`replace: true` prevents it from creating duplicate routes in browser history stack.

### Create a hook to revalidate on focus

    import { useEffect } from "react";
    
    export const useRevalidateOnFocus = ({
      enabled = false,
    }: {
      enabled?: boolean;
    }) => {
      let revalidate = useRevalidate();
    
      useEffect(
        function revalidateOnFocus() {
          if (!enabled) return;
          function onFocus() {
            revalidate();
          }
          window.addEventListener("focus", onFocus);
          return () => window.removeEventListener("focus", onFocus);
        },
        // eslint-disable-next-line react-hooks/exhaustive-deps
        [revalidate]
      );
    
      useEffect(
        function revalidateOnVisibilityChange() {
          if (!enabled) return;
          function onVisibilityChange() {
            revalidate();
          }
          window.addEventListener("visibilitychange", onVisibilityChange);
          return () =>
            window.removeEventListener("visibilitychange", onVisibilityChange);
        },
        // eslint-disable-next-line react-hooks/exhaustive-deps
        [revalidate]
      );
    };
    

### Create a hook to revalidate based on interval

    import { useEffect } from "react";
    
    export const useRevalidateOnInterval = ({
      enabled = false,
      interval = 1000,
    }: {
      enabled?: boolean;
      interval?: number;
    }) => {
      let revalidate = useRevalidate();
      useEffect(
        function revalidateOnInterval() {
          if (!enabled) return;
          let intervalId = setInterval(revalidate, interval);
          return () => clearInterval(intervalId);
        },
        // eslint-disable-next-line react-hooks/exhaustive-deps
        [revalidate]
      );
    };
    

### Use the hooks we created

Now just call the hook in route where loader is in.

    export function User() {
        useRevalidateOnInterval({
          enabled: true,
          interval: 5 * 1000,
        });
        const { user } = useLoaderData<LoaderData>();
    
        return <p>{user.username}</p>;
    }
    

in the above example it would re-validate user every 5 seconds.

---

*Originally published on [Vanxh](https://paragraph.com/@vanxh/data-revalidation-in-remix)*
