Skip to content

Commit 173578d

Browse files
committed
Merge branch 'dev' into brophdawg11/strip-basename-getkey
2 parents de77321 + 8972f30 commit 173578d

File tree

85 files changed

+633
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+633
-176
lines changed

.changeset/non-serializable-state.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

.changeset/revalidate-with-hash.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/stale-birds-travel.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/start-transition-support.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

.changeset/sync-window-location.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@remix-run/router": patch
3+
"react-router-dom": patch
4+
---
5+
6+
Call `window.history.pushState/replaceState` before updating React Router state (instead of after) so that `window.location` matches `useLocation` during synchronous React 17 rendering. However, generally apps should not be relying on `window.location` and should always reference `useLocation` when possible, as `window.location` will not be in sync 100% of the time (due to `popstate` events, concurrent mode, etc.)

contributors.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- AmRo045
1515
- amsal
1616
- andreiduca
17+
- antonmontrezor
1718
- appden
1819
- arnassavickas
1920
- aroyan
@@ -124,6 +125,7 @@
124125
- lordofthecactus
125126
- LordThi
126127
- loun4
128+
- lounsbrough
127129
- lpaube
128130
- lqze
129131
- lukerSpringTree
@@ -191,6 +193,7 @@
191193
- thisiskartik
192194
- thomasverleye
193195
- ThornWu
196+
- tiborbarsi
194197
- timdorr
195198
- TkDodo
196199
- tkindy
@@ -215,3 +218,4 @@
215218
- yionr
216219
- yuleicul
217220
- zheng-chuang
221+
- holynewbie

docs/components/routes.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface RoutesProps {
1717
</Routes>;
1818
```
1919

20-
<docs-info>If you're using a data router like [`createBrowserRouter`][createbrowserrouter] it is uncommon to use this component as it does not participate in data loading.</docs-info>
20+
<docs-info>If you're using a data router like [`createBrowserRouter`][createbrowserrouter] it is uncommon to use this component as routes defined as part of a descendant `<Routes>` tree cannot leverage the [Data APIs][data-apis] available to [`RouterProvider`][router-provider] apps. You **can and should** use this component within your `RouterProvider` application [while you are migrating][migrating-to-router-provider].</docs-info>
2121

2222
Whenever the location changes, `<Routes>` looks through all its child routes to find the best match and renders that branch of the UI. `<Route>` elements may be nested to indicate nested UI, which also correspond to nested URL paths. Parent routes render their child routes by rendering an [`<Outlet>`][outlet].
2323

@@ -38,3 +38,6 @@ Whenever the location changes, `<Routes>` looks through all its child routes to
3838
[outlet]: ./outlet
3939
[use-route]: ../hooks/use-routes
4040
[createbrowserrouter]: ../routers/create-browser-router
41+
[data-apis]: ../routers/picking-a-router#data-apis
42+
[router-provider]: ../routers/router-provider
43+
[migrating-to-router-provider]: ../upgrading/v6-data

docs/guides/ssr.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ Once we've sent the HTML back to the browser, we'll need to "hydrate" the applic
143143

144144
```jsx filename=entry-client.jsx lines=[10-15]
145145
import * as React from "react";
146-
import ReactDOM from "react-dom/client";
146+
import * as ReactDOM from "react-dom/client";
147147
import {
148148
createBrowserRouter,
149149
RouterProvider,
@@ -275,7 +275,7 @@ app.listen(3000);
275275
And finally, you'll need a similar file to "hydrate" the app with your JavaScript bundle that includes the very same `App` component. Note the use of `BrowserRouter` instead of `StaticRouter`.
276276
277277
```js filename=client.entry.js
278-
import ReactDOM from "react-dom";
278+
import * as ReactDOM from "react-dom";
279279
import { BrowserRouter } from "react-router-dom";
280280
import App from "./App";
281281

docs/hooks/use-navigate.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: useNavigate
44

55
# `useNavigate`
66

7-
<docs-warning>It's usually better to use [`redirect`][redirect] in loaders and actions than this hook</docs-warning>
7+
<docs-warning>It's usually better to use [`redirect`][redirect] in [`loaders`][loaders] and [`actions`][actions] than this hook</docs-warning>
88

99
The `useNavigate` hook returns a function that lets you navigate programmatically, for example in an effect:
1010

@@ -50,3 +50,5 @@ The `navigate` function has two signatures:
5050
If using `replace: true`, the navigation will replace the current entry in the history stack instead of adding a new one.
5151

5252
[redirect]: ../fetch/redirect
53+
[loaders]: ../route/loader
54+
[actions]: ../route/action

docs/route/action.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,62 @@ You can `throw` in your action to break out of the current call stack (stop runn
129129

130130
For more details and expanded use cases, read the [errorElement][errorelement] documentation.
131131

132+
## Handling multiple actions per route
133+
134+
A fairly common question that pops up is _"What if I need to handle multiple different behaviors in my action?"_ There's a few ways to accomplish this, but usually the simplest is to put a `name`/`value` on your `<button type="submit">` and use that in the action to decide which code to execute (that's right - submitting [buttons][button] can have name/value attributes!):
135+
136+
```jsx lines=[3,5,10,30-32,42-44]
137+
async function action({ request }) {
138+
let formData = await request.formData();
139+
let intent = formData.get("intent");
140+
141+
if (intent === "edit") {
142+
await editSong(formData);
143+
return { ok: true };
144+
}
145+
146+
if (intent === "add") {
147+
await addSong(formData);
148+
return { ok: true };
149+
}
150+
151+
throw json(
152+
{ message: "Invalid intent" },
153+
{ status: 400 }
154+
);
155+
}
156+
157+
function Component() {
158+
let song = useLoaderData();
159+
160+
// When the song exists, show an edit form
161+
if (song) {
162+
return (
163+
<Form method="post">
164+
<p>Edit song lyrics:</p>
165+
{/* Edit song inputs */}
166+
<button type="submit" name="intent" value="edit">
167+
Edit
168+
</button>
169+
</Form>
170+
);
171+
}
172+
173+
// Otherwise show a form to add a new song
174+
return (
175+
<Form method="post">
176+
<p>Add new lyrics:</p>
177+
{/* Add song inputs */}
178+
<button type="submit" name="intent" value="add">
179+
Add
180+
</button>
181+
</Form>
182+
);
183+
}
184+
```
185+
186+
If a button name/value isn't right for your use case, you could also use a hidden input to send and `intent` or you could submit different HTTP methods via the [`<Form method>`][form-method] prop (`POST` for add, `PUT`/`PATCH` for edit, `DELETE` for remove).
187+
132188
[loader]: ./loader
133189
[pickingarouter]: ../routers/picking-a-router
134190
[dynamicsegments]: ./route#dynamic-segments
@@ -146,3 +202,5 @@ For more details and expanded use cases, read the [errorElement][errorelement] d
146202
[useactiondata]: ../hooks/use-action-data
147203
[returningresponses]: ./loader#returning-responses
148204
[createbrowserrouter]: ../routers/create-browser-router
205+
[button]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button
206+
[form-method]: ../components/form#method

0 commit comments

Comments
 (0)