diff --git a/.changeset/pre.json b/.changeset/pre.json
index 5292247897..370fee1430 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -36,5 +36,10 @@
"@playground/split-route-modules-spa": "0.0.0",
"@playground/vite-plugin-cloudflare": "0.0.0"
},
- "changesets": []
+ "changesets": [
+ "breezy-planes-roll",
+ "green-pens-push",
+ "quick-eels-join",
+ "six-lobsters-think"
+ ]
}
diff --git a/packages/create-react-router/CHANGELOG.md b/packages/create-react-router/CHANGELOG.md
index da45cd74b2..b568ce6a01 100644
--- a/packages/create-react-router/CHANGELOG.md
+++ b/packages/create-react-router/CHANGELOG.md
@@ -1,5 +1,7 @@
# `create-react-router`
+## 7.9.4-pre.0
+
## 7.9.3
## 7.9.2
diff --git a/packages/create-react-router/package.json b/packages/create-react-router/package.json
index f0eab96b1a..12b2b43891 100644
--- a/packages/create-react-router/package.json
+++ b/packages/create-react-router/package.json
@@ -1,6 +1,6 @@
{
"name": "create-react-router",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Create a new React Router app",
"homepage": "https://reactrouter.com",
"bugs": {
diff --git a/packages/react-router-architect/CHANGELOG.md b/packages/react-router-architect/CHANGELOG.md
index 5ec74a1162..6b490f824c 100644
--- a/packages/react-router-architect/CHANGELOG.md
+++ b/packages/react-router-architect/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/architect`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+ - `@react-router/node@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-architect/package.json b/packages/react-router-architect/package.json
index 9b63583c6f..9338237309 100644
--- a/packages/react-router-architect/package.json
+++ b/packages/react-router-architect/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/architect",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Architect server request handler for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-cloudflare/CHANGELOG.md b/packages/react-router-cloudflare/CHANGELOG.md
index d74b9aa8d9..514ce4ed59 100644
--- a/packages/react-router-cloudflare/CHANGELOG.md
+++ b/packages/react-router-cloudflare/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/cloudflare`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-cloudflare/package.json b/packages/react-router-cloudflare/package.json
index 249f43f0f8..af600ec3fe 100644
--- a/packages/react-router-cloudflare/package.json
+++ b/packages/react-router-cloudflare/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/cloudflare",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Cloudflare platform abstractions for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-dev/CHANGELOG.md b/packages/react-router-dev/CHANGELOG.md
index 2d0aa8e6df..9639e668e0 100644
--- a/packages/react-router-dev/CHANGELOG.md
+++ b/packages/react-router-dev/CHANGELOG.md
@@ -1,5 +1,115 @@
# `@react-router/dev`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Update `valibot` dependency to `^1.1.0` ([#14379](https://github.com/remix-run/react-router/pull/14379))
+- New (unstable) `useRoute` hook for accessing data from specific routes ([#14407](https://github.com/remix-run/react-router/pull/14407))
+
+ For example, let's say you have an `admin` route somewhere in your app and you want any child routes of `admin` to all have access to the `loaderData` and `actionData` from `admin.`
+
+ ```tsx
+ // app/routes/admin.tsx
+ import { Outlet } from "react-router";
+
+ export const loader = () => ({ message: "Hello, loader!" });
+
+ export const action = () => ({ count: 1 });
+
+ export default function Component() {
+ return (
+
+ {/* ... */}
+
+ {/* ... */}
+
+ );
+ }
+ ```
+
+ You might even want to create a reusable widget that all of the routes nested under `admin` could use:
+
+ ```tsx
+ import { unstable_useRoute as useRoute } from "react-router";
+
+ export function AdminWidget() {
+ // How to get `message` and `count` from `admin` route?
+ }
+ ```
+
+ In framework mode, `useRoute` knows all your app's routes and gives you TS errors when invalid route IDs are passed in:
+
+ ```tsx
+ export function AdminWidget() {
+ const admin = useRoute("routes/dmin");
+ // ^^^^^^^^^^^
+ }
+ ```
+
+ `useRoute` returns `undefined` if the route is not part of the current page:
+
+ ```tsx
+ export function AdminWidget() {
+ const admin = useRoute("routes/admin");
+ if (!admin) {
+ throw new Error(`AdminWidget used outside of "routes/admin"`);
+ }
+ }
+ ```
+
+ Note: the `root` route is the exception since it is guaranteed to be part of the current page.
+ As a result, `useRoute` never returns `undefined` for `root`.
+
+ `loaderData` and `actionData` are marked as optional since they could be accessed before the `action` is triggered or after the `loader` threw an error:
+
+ ```tsx
+ export function AdminWidget() {
+ const admin = useRoute("routes/admin");
+ if (!admin) {
+ throw new Error(`AdminWidget used outside of "routes/admin"`);
+ }
+ const { loaderData, actionData } = admin;
+ console.log(loaderData);
+ // ^? { message: string } | undefined
+ console.log(actionData);
+ // ^? { count: number } | undefined
+ }
+ ```
+
+ If instead of a specific route, you wanted access to the _current_ route's `loaderData` and `actionData`, you can call `useRoute` without arguments:
+
+ ```tsx
+ export function AdminWidget() {
+ const currentRoute = useRoute();
+ currentRoute.loaderData;
+ currentRoute.actionData;
+ }
+ ```
+
+ This usage is equivalent to calling `useLoaderData` and `useActionData`, but consolidates all route data access into one hook: `useRoute`.
+
+ Note: when calling `useRoute()` (without a route ID), TS has no way to know which route is the current route.
+ As a result, `loaderData` and `actionData` are typed as `unknown`.
+ If you want more type-safety, you can either narrow the type yourself with something like `zod` or you can refactor your app to pass down typed props to your `AdminWidget`:
+
+ ```tsx
+ export function AdminWidget({
+ message,
+ count,
+ }: {
+ message: string;
+ count: number;
+ }) {
+ /* ... */
+ }
+ ```
+
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+ - `@react-router/node@7.9.4-pre.0`
+ - `@react-router/serve@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-dev/package.json b/packages/react-router-dev/package.json
index fc0d72d1e2..9d558e4d0c 100644
--- a/packages/react-router-dev/package.json
+++ b/packages/react-router-dev/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/dev",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Dev tools and CLI for React Router",
"homepage": "https://reactrouter.com",
"bugs": {
diff --git a/packages/react-router-dom/CHANGELOG.md b/packages/react-router-dom/CHANGELOG.md
index 75c2ecb0ef..fb278e5db9 100644
--- a/packages/react-router-dom/CHANGELOG.md
+++ b/packages/react-router-dom/CHANGELOG.md
@@ -1,5 +1,12 @@
# react-router-dom
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-dom/package.json b/packages/react-router-dom/package.json
index 715770624e..07882a79b7 100644
--- a/packages/react-router-dom/package.json
+++ b/packages/react-router-dom/package.json
@@ -1,6 +1,6 @@
{
"name": "react-router-dom",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Declarative routing for React web applications",
"keywords": [
"react",
diff --git a/packages/react-router-express/CHANGELOG.md b/packages/react-router-express/CHANGELOG.md
index d3e49f9170..2abc575995 100644
--- a/packages/react-router-express/CHANGELOG.md
+++ b/packages/react-router-express/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/express`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+ - `@react-router/node@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-express/package.json b/packages/react-router-express/package.json
index 18f5bf6a13..69ccc57335 100644
--- a/packages/react-router-express/package.json
+++ b/packages/react-router-express/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/express",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Express server request handler for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-fs-routes/CHANGELOG.md b/packages/react-router-fs-routes/CHANGELOG.md
index 0153883a9c..3bb3c8ae43 100644
--- a/packages/react-router-fs-routes/CHANGELOG.md
+++ b/packages/react-router-fs-routes/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/fs-routes`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `@react-router/dev@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-fs-routes/package.json b/packages/react-router-fs-routes/package.json
index d7728fd930..1b8d3d223e 100644
--- a/packages/react-router-fs-routes/package.json
+++ b/packages/react-router-fs-routes/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/fs-routes",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "File system routing conventions for React Router, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-node/CHANGELOG.md b/packages/react-router-node/CHANGELOG.md
index 8955ab93d2..5fe4f76bfa 100644
--- a/packages/react-router-node/CHANGELOG.md
+++ b/packages/react-router-node/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/node`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Validate format of incoming session ids ([#14426](https://github.com/remix-run/react-router/pull/14426))
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-node/package.json b/packages/react-router-node/package.json
index be542771c3..91ea0eeaef 100644
--- a/packages/react-router-node/package.json
+++ b/packages/react-router-node/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/node",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Node.js platform abstractions for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
index 7d95d12953..63d3bfa64a 100644
--- a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
+++ b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/remix-config-routes-adapter`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `@react-router/dev@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-remix-routes-option-adapter/package.json b/packages/react-router-remix-routes-option-adapter/package.json
index 691b5353ab..17994e4ec1 100644
--- a/packages/react-router-remix-routes-option-adapter/package.json
+++ b/packages/react-router-remix-routes-option-adapter/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/remix-routes-option-adapter",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Adapter for Remix's \"routes\" config option, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-serve/CHANGELOG.md b/packages/react-router-serve/CHANGELOG.md
index cb2c8edc65..0ef42b1322 100644
--- a/packages/react-router-serve/CHANGELOG.md
+++ b/packages/react-router-serve/CHANGELOG.md
@@ -1,5 +1,14 @@
# `@react-router/serve`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.4-pre.0`
+ - `@react-router/node@7.9.4-pre.0`
+ - `@react-router/express@7.9.4-pre.0`
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router-serve/package.json b/packages/react-router-serve/package.json
index 4d42b286a5..121fea9074 100644
--- a/packages/react-router-serve/package.json
+++ b/packages/react-router-serve/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/serve",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Production application server for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md
index 2f0d19ed90..5d713cc6fe 100644
--- a/packages/react-router/CHANGELOG.md
+++ b/packages/react-router/CHANGELOG.md
@@ -1,5 +1,110 @@
# `react-router`
+## 7.9.4-pre.0
+
+### Patch Changes
+
+- handle external redirects in from server actions ([#14400](https://github.com/remix-run/react-router/pull/14400))
+- New (unstable) `useRoute` hook for accessing data from specific routes ([#14407](https://github.com/remix-run/react-router/pull/14407))
+
+ For example, let's say you have an `admin` route somewhere in your app and you want any child routes of `admin` to all have access to the `loaderData` and `actionData` from `admin.`
+
+ ```tsx
+ // app/routes/admin.tsx
+ import { Outlet } from "react-router";
+
+ export const loader = () => ({ message: "Hello, loader!" });
+
+ export const action = () => ({ count: 1 });
+
+ export default function Component() {
+ return (
+
+ {/* ... */}
+
+ {/* ... */}
+
+ );
+ }
+ ```
+
+ You might even want to create a reusable widget that all of the routes nested under `admin` could use:
+
+ ```tsx
+ import { unstable_useRoute as useRoute } from "react-router";
+
+ export function AdminWidget() {
+ // How to get `message` and `count` from `admin` route?
+ }
+ ```
+
+ In framework mode, `useRoute` knows all your app's routes and gives you TS errors when invalid route IDs are passed in:
+
+ ```tsx
+ export function AdminWidget() {
+ const admin = useRoute("routes/dmin");
+ // ^^^^^^^^^^^
+ }
+ ```
+
+ `useRoute` returns `undefined` if the route is not part of the current page:
+
+ ```tsx
+ export function AdminWidget() {
+ const admin = useRoute("routes/admin");
+ if (!admin) {
+ throw new Error(`AdminWidget used outside of "routes/admin"`);
+ }
+ }
+ ```
+
+ Note: the `root` route is the exception since it is guaranteed to be part of the current page.
+ As a result, `useRoute` never returns `undefined` for `root`.
+
+ `loaderData` and `actionData` are marked as optional since they could be accessed before the `action` is triggered or after the `loader` threw an error:
+
+ ```tsx
+ export function AdminWidget() {
+ const admin = useRoute("routes/admin");
+ if (!admin) {
+ throw new Error(`AdminWidget used outside of "routes/admin"`);
+ }
+ const { loaderData, actionData } = admin;
+ console.log(loaderData);
+ // ^? { message: string } | undefined
+ console.log(actionData);
+ // ^? { count: number } | undefined
+ }
+ ```
+
+ If instead of a specific route, you wanted access to the _current_ route's `loaderData` and `actionData`, you can call `useRoute` without arguments:
+
+ ```tsx
+ export function AdminWidget() {
+ const currentRoute = useRoute();
+ currentRoute.loaderData;
+ currentRoute.actionData;
+ }
+ ```
+
+ This usage is equivalent to calling `useLoaderData` and `useActionData`, but consolidates all route data access into one hook: `useRoute`.
+
+ Note: when calling `useRoute()` (without a route ID), TS has no way to know which route is the current route.
+ As a result, `loaderData` and `actionData` are typed as `unknown`.
+ If you want more type-safety, you can either narrow the type yourself with something like `zod` or you can refactor your app to pass down typed props to your `AdminWidget`:
+
+ ```tsx
+ export function AdminWidget({
+ message,
+ count,
+ }: {
+ message: string;
+ count: number;
+ }) {
+ /* ... */
+ }
+ ```
+
## 7.9.3
### Patch Changes
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index 563bcad27c..1f1ef9ac12 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
{
"name": "react-router",
- "version": "7.9.3",
+ "version": "7.9.4-pre.0",
"description": "Declarative routing for React",
"keywords": [
"react",