useTransition

Watch the 📼 Remix Singles: Pending UI, Clearing Inputs After Form Submissions, and Optimistic UI

This hook tells you everything you need to know about a page transition to build pending navigation indicators and optimistic UI on data mutations. Things like:

import { useTransition } from "@remix-run/react";

function SomeComponent() {
  const transition = useTransition();
  transition.state;
  transition.type;
  transition.submission;
  transition.location;
}

transition.state

You can know the state of the transition with transition.state. It will be one of:

Normal navigation's transition as follows:

idle → loading → idle

GET form submissions transition as follows:

idle → submitting → idle

Form submissions with POST, PUT, PATCH, or DELETE transition as follows:

idle → submitting → loading → idle
function SubmitButton() {
  const transition = useTransition();

  const text =
    transition.state === "submitting"
      ? "Saving..."
      : transition.state === "loading"
      ? "Saved!"
      : "Go";

  return <button type="submit">{text}</button>;
}

transition.type

Most pending UI only cares about transition.state, but the transition can tell you even more information on transition.type.

Remix calls your route loaders at various times, like on normal link clicks or after a form submission completes. If you'd like to build pending indication that is more granular than "loading" and "submitting", use the transition.type.

Depending on the transition state, the types can be the following:

function SubmitButton() {
  const transition = useTransition();

  const loadTexts = {
    actionRedirect: "Data saved, redirecting...",
    actionReload: "Data saved, reloading fresh data...",
  };

  const text =
    transition.state === "submitting"
      ? "Saving..."
      : transition.state === "loading"
      ? loadTexts[transition.type] || "Loading..."
      : "Go";

  return <button type="submit">{text}</button>;
}

transition.submission

Any transition that started from a <Form> or useSubmit will have your form's submission attached to it. This is primarily useful to build "Optimistic UI" with the submission.formData FormData object.

TODO: Example

transition.location

This tells you what the next location is going to be. It's most useful when matching against the next URL for custom links and hooks.

For example, this Link knows when its page is loading and about to become active:

import { Link, useResolvedPath } from "@remix-run/react";

function PendingLink({ to, children }) {
  const transition = useTransition();
  const path = useResolvedPath(to);

  const isPending =
    transition.state === "loading" &&
    transition.location.pathname === path.pathname;

  return (
    <Link
      data-pending={isPending ? "true" : null}
      to={to}
      children={children}
    />
  );
}

Note that this link will not appear "pending" if a form is being submitted to the URL the link points to, because we only do this for "loading" states. The form will contain the pending UI for when the state is "submitting", once the action is complete, then the link will go pending.