From a3497b9afc290279fe8d24fc0309a929f1bbedcb Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 12 Sep 2024 12:53:29 -0400 Subject: [PATCH] Stabilize viewTransiton and flushSync options --- .changeset/stabilize-flush-sync.md | 7 +++ .changeset/stabilize-view-transitions.md | 7 +++ docs/components/form.md | 6 +-- docs/components/link.md | 16 +++---- docs/components/nav-link.md | 8 ++-- docs/hooks/use-fetcher.md | 4 +- docs/hooks/use-navigate.md | 16 +++---- docs/hooks/use-submit.md | 6 +-- docs/hooks/use-view-transition-state.md | 15 +++--- docs/routers/picking-a-router.md | 4 +- .../__tests__/data-browser-router-test.tsx | 6 +-- .../__tests__/flush-sync-navigations-test.tsx | 40 ++++++++-------- packages/react-router-dom/dom.ts | 4 +- packages/react-router-dom/index.tsx | 48 +++++++++---------- packages/react-router/lib/context.ts | 4 +- packages/router/__tests__/flush-sync-test.ts | 38 +++++++-------- .../router/__tests__/view-transition-test.ts | 26 +++++----- packages/router/router.ts | 18 +++---- 18 files changed, 143 insertions(+), 130 deletions(-) create mode 100644 .changeset/stabilize-flush-sync.md create mode 100644 .changeset/stabilize-view-transitions.md diff --git a/.changeset/stabilize-flush-sync.md b/.changeset/stabilize-flush-sync.md new file mode 100644 index 0000000000..950ebe9d9f --- /dev/null +++ b/.changeset/stabilize-flush-sync.md @@ -0,0 +1,7 @@ +--- +"react-router-dom": minor +"react-router": minor +"@remix-run/router": minor +--- + +Stabilize the `unstable_flushSync` option for navigations and fetchers diff --git a/.changeset/stabilize-view-transitions.md b/.changeset/stabilize-view-transitions.md new file mode 100644 index 0000000000..1cc8d1c5ca --- /dev/null +++ b/.changeset/stabilize-view-transitions.md @@ -0,0 +1,7 @@ +--- +"react-router-dom": minor +"react-router": minor +"@remix-run/router": minor +--- + +Stabilize the `unstable_viewTransition` option for navigations and the corresponding `unstable_useViewTransitionState` hook diff --git a/docs/components/form.md b/docs/components/form.md index b095b62634..37f1d81ea3 100644 --- a/docs/components/form.md +++ b/docs/components/form.md @@ -27,7 +27,7 @@ interface FormProps reloadDocument?: boolean; replace?: boolean; state?: any; - unstable_viewTransition?: boolean; + viewTransition?: boolean; } ``` @@ -281,9 +281,9 @@ If you are using [``][scrollrestoration], this lets you preve See also: [``][link-preventscrollreset] -## `unstable_viewTransition` +## `viewTransition` -The `unstable_viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. If you need to apply specific styles for this view transition, you will also need to leverage the [`unstable_useViewTransitionState()`][use-view-transition-state]. +The `viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. If you need to apply specific styles for this view transition, you will also need to leverage the [`useViewTransitionState()`][use-view-transition-state]. Please note that this API is marked unstable and may be subject to breaking changes without a major release diff --git a/docs/components/link.md b/docs/components/link.md index 3fccea2ee3..946c86ed9c 100644 --- a/docs/components/link.md +++ b/docs/components/link.md @@ -23,7 +23,7 @@ interface LinkProps reloadDocument?: boolean; replace?: boolean; state?: any; - unstable_viewTransition?: boolean; + viewTransition?: boolean; } type To = string | Partial; @@ -171,24 +171,24 @@ let { state } = useLocation(); The `reloadDocument` property can be used to skip client side routing and let the browser handle the transition normally (as if it were an ``). -## `unstable_viewTransition` +## `viewTransition` -The `unstable_viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`: +The `viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`: ```jsx - + Click me ``` -If you need to apply specific styles for this view transition, you will also need to leverage the [`unstable_useViewTransitionState()`][use-view-transition-state] hook (or check out the `transitioning` class and `isTransitioning` render prop in [NavLink][navlink]): +If you need to apply specific styles for this view transition, you will also need to leverage the [`useViewTransitionState()`][use-view-transition-state] hook (or check out the `transitioning` class and `isTransitioning` render prop in [NavLink][navlink]): ```jsx function ImageLink(to) { const isTransitioning = - unstable_useViewTransitionState(to); + useViewTransitionState(to); return ( - +

`unstable_viewTransition` only works when using a data router, see [Picking a Router][picking-a-router] +`viewTransition` only works when using a data router, see [Picking a Router][picking-a-router] Please note that this API is marked unstable and may be subject to breaking changes without a major release diff --git a/docs/components/nav-link.md b/docs/components/nav-link.md index b81514c4d7..7e7fc1a874 100644 --- a/docs/components/nav-link.md +++ b/docs/components/nav-link.md @@ -123,9 +123,9 @@ When a `NavLink` is active it will automatically apply `` The `reloadDocument` property can be used to skip client side routing and let the browser handle the transition normally (as if it were an ``). -## `unstable_viewTransition` +## `viewTransition` -The `unstable_viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. By default, during the transition a `transitioning` class will be added to the `` element that you can use to customize the view transition. +The `viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. By default, during the transition a `transitioning` class will be added to the `` element that you can use to customize the view transition. ```css a.transitioning p { @@ -138,7 +138,7 @@ a.transitioning img { ``` ```jsx - +

Image Number {idx}

{`Img @@ -147,7 +147,7 @@ a.transitioning img { You may also use the `className`/`style` props or the render props passed to `children` to further customize based on the `isTransitioning` value. ```jsx - + {({ isTransitioning }) => ( <>

Any `fetcher.load` calls that are active on the page will be re-executed as part of revalidation (either after a navigation submission, another fetcher submission, or a `useRevalidator()` call) -#### `options.unstable_flushSync` +#### `options.flushSync` -The `unstable_flushSync` option tells React Router DOM to wrap the initial state update for this `fetcher.load` in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM. +The `flushSync` option tells React Router DOM to wrap the initial state update for this `fetcher.load` in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM. Please note that this API is marked unstable and may be subject to breaking changes without a major release diff --git a/docs/hooks/use-navigate.md b/docs/hooks/use-navigate.md index 978d3bf173..90911e306f 100644 --- a/docs/hooks/use-navigate.md +++ b/docs/hooks/use-navigate.md @@ -20,8 +20,8 @@ interface NavigateOptions { state?: any; preventScrollReset?: boolean; relative?: RelativeRoutingType; - unstable_flushSync?: boolean; - unstable_viewTransition?: boolean; + flushSync?: boolean; + viewTransition?: boolean; } type RelativeRoutingType = "route" | "path"; @@ -114,19 +114,19 @@ new URL("..", window.origin + location.pathname + "/"); // 'https://remix.run/docs/en/main/start/' ``` -## `options.unstable_flushSync` +## `options.flushSync` -The `unstable_flushSync` option tells React Router DOM to wrap the initial state update for this navigation in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM. +The `flushSync` option tells React Router DOM to wrap the initial state update for this navigation in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM. -`unstable_flushSync` only works when using a data router, see [Picking a Router][picking-a-router] +`flushSync` only works when using a data router, see [Picking a Router][picking-a-router] Please note that this API is marked unstable and may be subject to breaking changes without a major release -## `options.unstable_viewTransition` +## `options.viewTransition` -The `unstable_viewTransition` option enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. If you need to apply specific styles for this view transition, you will also need to leverage the [`unstable_useViewTransitionState()`][use-view-transition-state]. +The `viewTransition` option enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. If you need to apply specific styles for this view transition, you will also need to leverage the [`useViewTransitionState()`][use-view-transition-state]. -`unstable_viewTransition` only works when using a data router, see [Picking a Router][picking-a-router] +`viewTransition` only works when using a data router, see [Picking a Router][picking-a-router] Please note that this API is marked unstable and may be subject to breaking changes without a major release diff --git a/docs/hooks/use-submit.md b/docs/hooks/use-submit.md index 83e0a14650..f43b2cfd28 100644 --- a/docs/hooks/use-submit.md +++ b/docs/hooks/use-submit.md @@ -160,11 +160,11 @@ Because submissions are navigations, the options may also contain the other navi - `relative` - `replace` - `state` -- `unstable_viewTransition` +- `viewTransition` -### `options.unstable_flushSync` +### `options.flushSync` -The `unstable_flushSync` option tells React Router DOM to wrap the initial state update for this submission in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM. +The `flushSync` option tells React Router DOM to wrap the initial state update for this submission in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM. Please note that this API is marked unstable and may be subject to breaking changes without a major release diff --git a/docs/hooks/use-view-transition-state.md b/docs/hooks/use-view-transition-state.md index 83164bb9d7..91819c5266 100644 --- a/docs/hooks/use-view-transition-state.md +++ b/docs/hooks/use-view-transition-state.md @@ -1,14 +1,14 @@ --- -title: unstable_useViewTransitionState +title: useViewTransitionState --- -# `unstable_useViewTransitionState` +# `useViewTransitionState`

Type declaration ```tsx -declare function unstable_useViewTransitionState( +declare function useViewTransitionState( to: To, opts: { relative?: "route" : "path" } = {} ): boolean; @@ -24,17 +24,16 @@ interface Path {
-This hook returns `true` when there is an active [View Transition][view-transitions] to the specified location. This can be used to apply finer-grained styles to elements to further customize the view transition. This requires that view transitions have been enabled for the given navigation via the [unstable_viewTransition][link-view-transition] prop on the `Link` (or the `Form`, `navigate`, or `submit` call). +This hook returns `true` when there is an active [View Transition][view-transitions] to the specified location. This can be used to apply finer-grained styles to elements to further customize the view transition. This requires that view transitions have been enabled for the given navigation via the [viewTransition][link-view-transition] prop on the `Link` (or the `Form`, `navigate`, or `submit` call). Consider clicking on an image in a list that you need to expand into the hero image on the destination page: ```jsx function NavImage({ src, alt, id }) { const to = `/images/${id}`; - const isTransitioning = - unstable_useViewTransitionState(to); + const isTransitioning = useViewTransitionState(to); return ( - + {alt} /a - + /b
-
+
@@ -7486,7 +7486,7 @@ function testDomRouter( Component() { return ( <> - + /page diff --git a/packages/react-router-dom/__tests__/flush-sync-navigations-test.tsx b/packages/react-router-dom/__tests__/flush-sync-navigations-test.tsx index 4d7fcff9e2..007823de8a 100644 --- a/packages/react-router-dom/__tests__/flush-sync-navigations-test.tsx +++ b/packages/react-router-dom/__tests__/flush-sync-navigations-test.tsx @@ -33,7 +33,7 @@ describe("flushSync", () => { <>

About

@@ -61,14 +61,14 @@ describe("flushSync", () => { expect(spy).toBeCalledTimes(1); expect(spy).toHaveBeenLastCalledWith( expect.anything(), - expect.objectContaining({ unstable_flushSync: false }) + expect.objectContaining({ flushSync: false }) ); fireEvent.click(screen.getByText("Go to /")); await waitFor(() => screen.getByText("Home")); expect(spy).toHaveBeenLastCalledWith( expect.anything(), - expect.objectContaining({ unstable_flushSync: true }) + expect.objectContaining({ flushSync: true }) ); expect(spy).toBeCalledTimes(2); @@ -110,7 +110,7 @@ describe("flushSync", () => { onClick={() => submit( {}, - { method: "post", action: "/", unstable_flushSync: true } + { method: "post", action: "/", flushSync: true } ) } > @@ -138,14 +138,14 @@ describe("flushSync", () => { fireEvent.click(screen.getByText("Go to /about")); await waitFor(() => screen.getByText("About")); expect(spy).toBeCalledTimes(2); - expect(spy.mock.calls[0][1].unstable_flushSync).toBe(false); - expect(spy.mock.calls[1][1].unstable_flushSync).toBe(false); + expect(spy.mock.calls[0][1].flushSync).toBe(false); + expect(spy.mock.calls[1][1].flushSync).toBe(false); fireEvent.click(screen.getByText("Go to /")); await waitFor(() => screen.getByText("Home")); expect(spy).toBeCalledTimes(4); - expect(spy.mock.calls[2][1].unstable_flushSync).toBe(true); - expect(spy.mock.calls[3][1].unstable_flushSync).toBe(false); + expect(spy.mock.calls[2][1].flushSync).toBe(true); + expect(spy.mock.calls[3][1].flushSync).toBe(false); router.dispose(); }); @@ -167,7 +167,7 @@ describe("flushSync", () => {
{`async:${fetcher1.data}:${fetcher1.state}`}