Skip to content

Commit 4da796a

Browse files
committed
fix(rsc): support react unstable_ViewTransition
1 parent 4ad108c commit 4da796a

File tree

9 files changed

+149
-42
lines changed

9 files changed

+149
-42
lines changed

.changeset/tidy-beans-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
fix(rsc): support react unstable_ViewTransition

packages/react-router/lib/rsc/browser.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -703,18 +703,6 @@ export function RSCHydratedRouter({
703703
}
704704
}, []);
705705

706-
let [location, setLocation] = React.useState(router.state.location);
707-
708-
React.useLayoutEffect(
709-
() =>
710-
router.subscribe((newState) => {
711-
if (newState.location !== location) {
712-
setLocation(newState.location);
713-
}
714-
}),
715-
[router, location],
716-
);
717-
718706
React.useEffect(() => {
719707
if (
720708
routeDiscovery === "lazy" ||
@@ -813,7 +801,7 @@ export function RSCHydratedRouter({
813801

814802
return (
815803
<RSCRouterContext.Provider value={true}>
816-
<RSCRouterGlobalErrorBoundary location={location}>
804+
<RSCRouterGlobalErrorBoundary location={router.state.location}>
817805
<FrameworkContext.Provider value={frameworkContext}>
818806
<RouterProvider router={router} flushSync={ReactDOM.flushSync} />
819807
</FrameworkContext.Provider>

playground/rsc-vite-framework/app/root.tsx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import type { Route } from "./+types/root";
22

3-
import { Meta, Link, Outlet, isRouteErrorResponse } from "react-router";
3+
import {
4+
Meta,
5+
Link,
6+
Outlet,
7+
isRouteErrorResponse,
8+
useNavigation,
9+
useRevalidator,
10+
} from "react-router";
411
import "./root.css";
512

613
export const meta = () => [{ title: "React Router Vite" }];
714

815
export function Layout({ children }: { children: React.ReactNode }) {
9-
console.log("Layout");
16+
const navigation = useNavigation();
17+
const revalidator = useRevalidator();
18+
19+
console.log({ navigation: navigation.state, revalidator: revalidator.state });
20+
1021
return (
1122
<html lang="en">
1223
<head>
@@ -17,13 +28,19 @@ export function Layout({ children }: { children: React.ReactNode }) {
1728
<body>
1829
<header>
1930
<h1 className="root__header">React Router Vite</h1>
31+
<p>Navigation: {navigation.state}</p>
32+
<p>Revalidation: {revalidator.state}</p>
2033
<nav>
2134
<ul>
2235
<li>
23-
<Link to="/">Home</Link>
36+
<Link to="/" viewTransition={true}>
37+
Home
38+
</Link>
2439
</li>
2540
<li>
26-
<Link to="/server-loader">Server loader</Link>
41+
<Link to="/server-loader" viewTransition={true}>
42+
Server loader
43+
</Link>
2744
</li>
2845
<li>
2946
<Link to="/client-loader">Client loader</Link>
@@ -51,8 +68,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
5168
);
5269
}
5370

54-
export function ServerComponent() {
55-
console.log("Root");
71+
export default function Root() {
5672
return (
5773
<>
5874
<Outlet />
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use server";
22

33
export async function log() {
4+
await new Promise((resolve) => setTimeout(resolve, 500));
45
console.log("hello from server");
56
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"use client";
2+
3+
// @ts-expect-error - needs React 19 types
4+
import { useFormStatus } from "react-dom";
5+
6+
export function SubmitButton() {
7+
const { pending } = useFormStatus();
8+
return <button type="submit">Submit{pending && "ing..."}</button>;
9+
}
Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,41 @@
1+
import { unstable_ViewTransition as ViewTransition } from "react";
12
import type { Route } from "./+types/route";
23
import { log } from "./actions";
4+
import { SubmitButton } from "./client";
35
import "./styles.css";
46

57
export function loader({}: Route.LoaderArgs) {
68
return "hello, world";
79
}
810

9-
export function ServerComponent({ loaderData }: Route.ComponentProps) {
11+
const items = ["blue", "green", "red", "yellow", "purple"];
12+
13+
export async function ServerComponent({ loaderData }: Route.ComponentProps) {
14+
await new Promise((resolve) => setTimeout(resolve, 500));
1015
return (
1116
<main>
1217
<h1 className="home__heading">Home</h1>
1318
<p>This is the home page.</p>
1419
<p>loaderData: {loaderData}</p>
1520
{/* @ts-expect-error React types for the repo are set to v18 */}
1621
<form action={log}>
17-
<button type="submit">Submit</button>
22+
<SubmitButton />
1823
</form>
24+
<ul>
25+
{items
26+
.sort(() => Math.random() - 0.5)
27+
.map((item) => (
28+
<ViewTransition key={item} name={item}>
29+
<div
30+
style={{
31+
backgroundColor: item,
32+
width: "100px",
33+
height: "100px",
34+
}}
35+
/>
36+
</ViewTransition>
37+
))}
38+
</ul>
1939
</main>
2040
);
2141
}

playground/rsc-vite-framework/app/routes/server-loader/route.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { unstable_ViewTransition as ViewTransition } from "react";
12
import type { Route } from "./+types/route";
23
import styles from "./styles.module.css";
34

@@ -12,6 +13,11 @@ export default function ServerLoaderRoute({
1213
<main>
1314
<h1 className={styles.heading}>Server loader</h1>
1415
<p>Loader data: {loaderData}</p>
16+
<ViewTransition name="blue">
17+
<div
18+
style={{ backgroundColor: "blue", width: "100px", height: "100px" }}
19+
/>
20+
</ViewTransition>
1521
</main>
1622
);
1723
}

playground/rsc-vite-framework/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
"@mjackson/node-fetch-server": "0.6.1",
3232
"compression": "^1.8.0",
3333
"express": "^4.21.2",
34-
"react": "^19.0.0",
35-
"react-dom": "^19.0.0",
34+
"react": "experimental",
35+
"react-dom": "experimental",
3636
"react-router": "workspace:*",
3737
"remix-utils": "^8.7.0"
3838
}

0 commit comments

Comments
 (0)