Skip to content

Commit

Permalink
Deprecate useTransition in favor of useNavigation (#5687)
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 authored Mar 7, 2023
1 parent e78a09b commit b33d098
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/deprecate-use-transition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/react": patch
---

Deprecate `useTransition` in favor of `useNavigation`
61 changes: 56 additions & 5 deletions docs/hooks/use-transition.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ title: useTransition

# `useTransition`

<docs-error>This API will be removed in v2 in favor of [`useNavigation`][use-navigation]. You can start using the new `useNavigation` hook today to make upgrading in the future easy, but you can keep using `useTransition` until v2.</docs-error>

---

<docs-success>Watch the <a href="https://www.youtube.com/playlist?list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">📼 Remix Singles</a>: <a href="https://www.youtube.com/watch?v=y4VLIFjFq8k&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">Pending UI</a>, <a href="https://www.youtube.com/watch?v=bMLej7bg5Zo&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">Clearing Inputs After Form Submissions</a>, and <a href="https://www.youtube.com/watch?v=EdB_nj01C80&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">Optimistic UI</a></docs-success>

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:
Expand Down Expand Up @@ -114,11 +118,62 @@ function SubmitButton() {
}
```

### Moving away from `transition.type`

The `type` field has been removed in the new `useNavigation` hook (which will replace `useTransition` in Remix v2). We've found that `state` is sufficient for almost all use-cases, and when it's not you can derive sub-types via `navigation.state` and other fields. Also note that the `loaderSubmission` type is now represented with `state: "loading"`. Here's a few examples:

```js
function Component() {
let navigation = useNavigation();

let isActionSubmission =
navigation.state === "submitting";

let isActionReload =
navigation.state === "loading" &&
navigation.formMethod != null &&
navigation.formMethod != "get" &&
// We had a submission navigation and are loading the submitted location
navigation.formAction === navigation.pathname;

let isActionRedirect =
navigation.state === "loading" &&
navigation.formMethod != null &&
navigation.formMethod != "get" &&
// We had a submission navigation and are now navigating to different location
navigation.formAction !== navigation.pathname;

let isLoaderSubmission =
navigation.state === "loading" &&
navigation.state.formMethod === "get" &&
// We had a loader submission and are navigating to the submitted location
navigation.formAction === navigation.pathname;

let isLoaderSubmissionRedirect =
navigation.state === "loading" &&
navigation.state.formMethod === "get" &&
// We had a loader submission and are navigating to a new location
navigation.formAction !== navigation.pathname;
}
```

## `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`][form-data] object.

TODO: Example
### Moving away from `transition.submission`

The `submission` field has been removed in the new `useNavigation` hook (which will replace `useTransition` in Remix v2) and the same sub-fields are now exposed directly on the `navigation`:

```js
function Component() {
let navigation = useNavigation();
// navigation.formMethod
// navigation.formAction
// navigation.formData
// navigation.formEncType
}
```

## `transition.location`

Expand Down Expand Up @@ -149,10 +204,6 @@ function PendingLink({ to, 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.

## v2 deprecation

This API will be removed in v2 in favor of [`useNavigation`][use-navigation]. You can start using the new `useNavigation` hook today to make upgrading in the future easy, but you can keep using `useTransition` before v2.

[usefetcher]: ./use-fetcher
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[use-navigation]: ./use-navigation
13 changes: 13 additions & 0 deletions packages/remix-react/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import type {
TransitionStates,
} from "./transition";
import { IDLE_TRANSITION, IDLE_FETCHER } from "./transition";
import { warnOnce } from "./warnings";

function useDataRouterContext() {
let context = React.useContext(DataRouterContext);
Expand Down Expand Up @@ -1173,11 +1174,23 @@ export function useActionData<T = AppData>(): SerializeFrom<T> | undefined {
* Returns everything you need to know about a page transition to build pending
* navigation indicators and optimistic UI on data mutations.
*
* @deprecated in favor of useNavigation
*
* @see https://remix.run/hooks/use-transition
*/
export function useTransition(): Transition {
let navigation = useNavigation();

React.useEffect(() => {
warnOnce(
false,
"⚠️ DEPRECATED: The `useTransition` hook has been deprecated in favor of " +
"`useNavigation` and will be removed in Remix v2. Please update your " +
"code to leverage `useNavigation`.\n\nSee https://remix.run/docs/hooks/use-transition " +
"and https://remix.run/docs/hooks/use-navigation for more information."
);
}, []);

return React.useMemo(
() => convertNavigationToTransition(navigation),
[navigation]
Expand Down
8 changes: 8 additions & 0 deletions packages/remix-react/warnings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const alreadyWarned: { [message: string]: boolean } = {};

export function warnOnce(condition: boolean, message: string): void {
if (!condition && !alreadyWarned[message]) {
alreadyWarned[message] = true;
console.warn(message);
}
}

0 comments on commit b33d098

Please sign in to comment.