Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
- ericschn
- ErlendS
- esadek
- facundofarias
- faergeek
- fernandojbf
- FilipJirsak
Expand Down
8 changes: 6 additions & 2 deletions docs/api/data-routers/RouterProvider.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/co
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react-router.RouterProvider.html)

Render the UI for the given [`DataRouter`](https://api.reactrouter.com/v7/interfaces/react-router.DataRouter.html). This component should
typically be at the top of an app's element tree.
typically be at the top of an app's element tree. The router prop should
be a single router instance created outside of the React tree. Avoid
creating new routers during React renders/re-renders.

```tsx
import { createBrowserRouter } from "react-router";
Expand Down Expand Up @@ -86,7 +88,9 @@ and is only present for render errors.

### router

The [`DataRouter`](https://api.reactrouter.com/v7/interfaces/react-router.DataRouter.html) instance to use for navigation and data fetching.
The [`DataRouter`](https://api.reactrouter.com/v7/interfaces/react-router.DataRouter.html) instance to use for navigation and data fetching. The
router prop should be a single router instance created outside of the React
tree. Avoid creating new routers during React renders/re-renders.

### useTransitions

Expand Down
4 changes: 4 additions & 0 deletions docs/api/data-routers/createBrowserRouter.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Create a new [data router](https://api.reactrouter.com/v7/interfaces/react-route
path via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
and [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState).

Data Routers should not be held in React state. You should create your router
once outside of the React tree and pass it to [`<RouterProvider>`](../data-routers/RouterProvider).
You can use `patchRoutesOnNavigation` to add additional routes programmatically.

## Signature

```tsx
Expand Down
4 changes: 4 additions & 0 deletions docs/api/data-routers/createHashRouter.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/do
Create a new [data router](https://api.reactrouter.com/v7/interfaces/react-router.DataRouter.html) that manages the application
path via the URL [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash).

Data Routers should not be held in React state. You should create your router
once outside of the React tree and pass it to [`<RouterProvider>`](../data-routers/RouterProvider).
You can use `patchRoutesOnNavigation` to add additional routes programmatically.

## Signature

```tsx
Expand Down
4 changes: 4 additions & 0 deletions docs/api/data-routers/createMemoryRouter.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Create a new [`DataRouter`](https://api.reactrouter.com/v7/interfaces/react-rout
in-memory [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
stack. Useful for non-browser environments without a DOM API.

Data Routers should not be held in React state. You should create your router
once outside of the React tree and pass it to [`<RouterProvider>`](../data-routers/RouterProvider).
You can use `patchRoutesOnNavigation` to add additional routes programmatically.

## Signature

```tsx
Expand Down
4 changes: 4 additions & 0 deletions docs/start/data/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ ReactDOM.createRoot(root).render(
);
```

<docs-info>Data Routers should not be held in React state. You should create your router
once outside of the React tree and pass it to `<RouterProvider>`. You can use
`patchRoutesOnNavigation` to add additional routes programmatically.</docs-info>

---

Next: [Routing](./routing)
4 changes: 4 additions & 0 deletions docs/start/framework/deploying.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,7 @@ Netlify maintains their own template for React Router. Checkout the [Netlify Gui
### EdgeOne Pages

EdgeOne Pages maintains their own template for React Router. Checkout the [EdgeOne Pages Guide](https://pages.edgeone.ai/document/framework-react-router) for more information.

### DeployHQ

DeployHQ maintains their own guide for deploying React Router v7 to your own server. Checkout the [DeployHQ Guide](https://www.deployhq.com/guides/deploy-react-router-from-github) for more information.
42 changes: 42 additions & 0 deletions packages/react-router/__tests__/dom/data-browser-router-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3574,6 +3574,48 @@ function testDomRouter(
"/foo/bar",
);
});

it("preserves encoded hash (%23) in form action and submission for param routes", async () => {
let actionPathname: string | null = null;
let router = createTestRouter(
[
{
path: "/",
children: [
{
path: ":slug",
action: ({ request }) => {
actionPathname = new URL(request.url).pathname;
return "slug action";
},
Component: () => {
let actionData = useActionData();
return (
<>
<Form method="post">
<button type="submit">Submit</button>
</Form>
{actionData && <p>{String(actionData)}</p>}
</>
);
},
},
],
},
],
{ window: getWindow("/%23routeWithHashTag") },
);
let { container } = render(<RouterProvider router={router} />);

expect(container.querySelector("form")?.getAttribute("action")).toBe(
"/%23routeWithHashTag",
);

fireEvent.click(screen.getByText("Submit"));
await waitFor(() => screen.getByText("slug action"));

expect(actionPathname).toBe("/%23routeWithHashTag");
});
});

describe("splat routes", () => {
Expand Down
12 changes: 10 additions & 2 deletions packages/react-router/lib/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ export interface MemoryRouterOpts {
* in-memory [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
* stack. Useful for non-browser environments without a DOM API.
*
* Data Routers should not be held in React state. You should create your router
* once outside of the React tree and pass it to {@link RouterProvider | `<RouterProvider>`}.
* You can use `patchRoutesOnNavigation` to add additional routes programmatically.
*
* @public
* @category Data Routers
* @mode data
Expand Down Expand Up @@ -374,7 +378,9 @@ export interface ClientOnErrorFunction {
*/
export interface RouterProviderProps {
/**
* The {@link DataRouter} instance to use for navigation and data fetching.
* The {@link DataRouter} instance to use for navigation and data fetching. The
* router prop should be a single router instance created outside of the React
* tree. Avoid creating new routers during React renders/re-renders.
*/
router: DataRouter;
/**
Expand Down Expand Up @@ -429,7 +435,9 @@ export interface RouterProviderProps {

/**
* Render the UI for the given {@link DataRouter}. This component should
* typically be at the top of an app's element tree.
* typically be at the top of an app's element tree. The router prop should
* be a single router instance created outside of the React tree. Avoid
* creating new routers during React renders/re-renders.
*
* ```tsx
* import { createBrowserRouter } from "react-router";
Expand Down
8 changes: 8 additions & 0 deletions packages/react-router/lib/dom/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,10 @@ export interface DOMRouterOpts {
* path via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
* and [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState).
*
* Data Routers should not be held in React state. You should create your router
* once outside of the React tree and pass it to {@link RouterProvider | `<RouterProvider>`}.
* You can use `patchRoutesOnNavigation` to add additional routes programmatically.
*
* @public
* @category Data Routers
* @mode data
Expand Down Expand Up @@ -667,6 +671,10 @@ export function createBrowserRouter(
* Create a new {@link DataRouter| data router} that manages the application
* path via the URL [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash).
*
* Data Routers should not be held in React state. You should create your router
* once outside of the React tree and pass it to {@link RouterProvider | `<RouterProvider>`}.
* You can use `patchRoutesOnNavigation` to add additional routes programmatically.
*
* @public
* @category Data Routers
* @mode data
Expand Down