🔄 Remix: shouldRevalidate

When you submit a form you might change some data, and the data currently shown on the page could be stale (outdated). Also, when you change the search params, the data on the page should be refreshed so the user can see the most up-to-date version of that page or screen.

In React Router 6.4+ and by extension Remix, you export a loader function that fetches data to be used for each route. And revalidation is when React Router call the loader functions so your page will always remain up-to-date in the above mentioned and similar cases.

In some cases where a nested route changes, React Router does some optimization and doesn't call all the matching loaders again, just necessary ones. But, on form submission and search param changes, every loader will be re-validated since they might depend on the search params to retrieve data.

When you have multiple nested routes, usually upper routes can be layout that don't change that often, for example there are very few cases where the root loader that might return user name and profile picture URL need to be refreshed.

React Router gives you a declarative way to define relationship between data (loader) and view (React component), and keeps the view up-to-date by giving it the most recent data. Though, there are times you want to opt-out of this functionality to optimize traffic or reduce latency of higher priority routes, this is done through shouldRevalidate function.

A good example is, when you change page search param in a paginated table nested inside a couple routes; or when loaders are called, and the user is offline at that time, the loaders might throw an error which makes your React component unmount, and renders the nearest ErrorBoundary, this is very cool, declarative and automatic. Unless, you need to keep your UI on the screen, even if the loaders need to be called again but it is not possible, you can tell React Router not to re-validate (calling loaders) by returning false from shouldRevalidate, like this:

// root.tsx

import type { ShouldRevalidateFunction } from "@remix-run/react"

export const shouldRevalidate: ShouldRevalidateFunction = ({
  defaultShouldRevalidate,
}) => {
  if ("onLine" in navigator && navigator.onLine === false) {
    return false
  }

  return defaultShouldRevalidate
}

It is recommended that your return defaultShouldRevalidate if no criteria that you provided are met, so React Router can still keep the default behavior, which is usually the desired behavior. As demonstrated in the code snippet above.

React Router provides many parameters so you have as much information as possible to base your criteria on. For example, in the case of form submission you have access to formMethod, formAction, formEncType, formData, json.

You even have access to actionResult that is returned from the action function, which you usually read from useActionData in your UI, this enables very advanced use-cases like conditional revalidation based on action results, which is a fancy way for saying you can control revalidation based on the result of your actions.

There are many other parameters provided to use, you can learn more about shouldRevalidate, it's params and it is behavior on React Router docs

remixshouldRevalidate