useTransition
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:
state === "idle"
state === "submitting"
state === "loading"
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.
This API will be removed in v2 in favor of useNavigation
. You can start using the new useNavigation
hook today to make upgrading in the future easy, but you can keep using useTransition
before v2.