Skip to content

Commit 7a1774f

Browse files
committed
Merge branch 'release-next'
2 parents bc25528 + 09b6cbe commit 7a1774f

Some content is hidden

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

58 files changed

+2776
-819
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: ⚙️ Deduplicate yarn.lock
2+
3+
on:
4+
push:
5+
branches:
6+
- dev
7+
paths:
8+
- ./yarn.lock
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
format:
16+
if: github.repository == 'remix-run/react-router'
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: ⬇️ Checkout repo
21+
uses: actions/checkout@v3
22+
23+
- name: ⎔ Setup node
24+
uses: actions/setup-node@v3
25+
with:
26+
node-version-file: ".nvmrc"
27+
cache: "yarn"
28+
29+
- name: ⚙️ Dedupe yarn.lock
30+
run: npx yarn-deduplicate && rm -rf ./node_modules && yarn
31+
32+
- name: 💪 Commit
33+
run: |
34+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
35+
git config --local user.name "github-actions[bot]"
36+
git add .
37+
if [ -z "$(git status --porcelain)" ]; then
38+
echo "💿 no deduplication needed"
39+
exit 0
40+
fi
41+
git commit -m "chore: deduplicate `yarn.lock`"
42+
git push
43+
echo "💿 https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)"

.github/workflows/test.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ concurrency:
2121

2222
jobs:
2323
test:
24-
name: 🧪 Test
24+
name: "🧪 Test: (Node: ${{ matrix.node }})"
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
node:
29+
- 16
30+
- 18
31+
2532
runs-on: ubuntu-latest
2633

2734
steps:
@@ -33,7 +40,7 @@ jobs:
3340
with:
3441
cache: yarn
3542
check-latest: true
36-
node-version-file: ".nvmrc"
43+
node-version: ${{ matrix.node }}
3744

3845
- name: Disable GitHub Actions Annotations
3946
run: |

contributors.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,4 @@
220220
- yionr
221221
- yuleicul
222222
- zheng-chuang
223+
- holynewbie

docs/hooks/use-fetcher.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ function SomeComponent() {
3838
// build your UI with these properties
3939
fetcher.state;
4040
fetcher.formData;
41+
fetcher.json;
42+
fetcher.text;
4143
fetcher.formMethod;
4244
fetcher.formAction;
4345
fetcher.data;
@@ -132,6 +134,8 @@ export function useIdleLogout() {
132134
}
133135
```
134136

137+
`fetcher.submit` is a wrapper around a [`useSubmit`][use-submit] call for the fetcher instance, so it also accepts the same options as `useSubmit`.
138+
135139
If you want to submit to an index route, use the [`?index` param][indexsearchparam].
136140

137141
If you find yourself calling this function inside of click handlers, you can probably simplify your code by using `<fetcher.Form>` instead.
@@ -200,6 +204,14 @@ function TaskCheckbox({ task }) {
200204
}
201205
```
202206

207+
## `fetcher.json`
208+
209+
When using `fetcher.submit(data, { formEncType: "application/json" })`, the submitted JSON is available via `fetcher.json`.
210+
211+
## `fetcher.text`
212+
213+
When using `fetcher.submit(data, { formEncType: "text/plain" })`, the submitted text is available via `fetcher.text`.
214+
203215
## `fetcher.formAction`
204216

205217
Tells you the action url the form is being submitted to.
@@ -231,3 +243,4 @@ fetcher.formMethod; // "post"
231243
[link]: ../components/link
232244
[form]: ../components/form
233245
[api-development-strategy]: ../guides/api-development-strategy
246+
[use-submit]: ./use-submit.md

docs/hooks/use-navigation.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ function SomeComponent() {
2323
navigation.state;
2424
navigation.location;
2525
navigation.formData;
26+
navigation.json;
27+
navigation.text;
2628
navigation.formAction;
2729
navigation.formMethod;
2830
}
@@ -92,6 +94,14 @@ Any POST, PUT, PATCH, or DELETE navigation that started from a `<Form>` or `useS
9294

9395
In the case of a GET form submission, `formData` will be empty and the data will be reflected in `navigation.location.search`.
9496

97+
## `navigation.json`
98+
99+
Any POST, PUT, PATCH, or DELETE navigation that started from a `useSubmit(payload, { encType: "application/json" })` will have your JSON value available in `navigation.json`.
100+
101+
## `navigation.text`
102+
103+
Any POST, PUT, PATCH, or DELETE navigation that started from a `useSubmit(payload, { encType: "text/plain" })` will have your text value available in `navigation.text`.
104+
95105
## `navigation.location`
96106

97107
This tells you what the next [location][location] is going to be.

docs/hooks/use-submit.md

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,66 @@ formData.append("cheese", "gouda");
7878
submit(formData);
7979
```
8080

81+
Or you can submit `URLSearchParams`:
82+
83+
```tsx
84+
let searchParams = new URLSearchParams();
85+
searchParams.append("cheese", "gouda");
86+
submit(searchParams);
87+
```
88+
89+
Or anything that the `URLSearchParams` constructor accepts:
90+
91+
```tsx
92+
submit("cheese=gouda&toasted=yes");
93+
submit([
94+
["cheese", "gouda"],
95+
["toasted", "yes"],
96+
]);
97+
```
98+
99+
The default behavior if you submit a JSON object for a POST submission is to encode the data into `FormData`:
100+
101+
```tsx
102+
submit({ key: "value" }, { method: "post" });
103+
// will serialize into request.formData() in your action
104+
// and will show up on useNavigation().formData during the navigation
105+
```
106+
107+
Or you can opt-into JSON encoding:
108+
109+
```tsx
110+
submit(
111+
{ key: "value" },
112+
{ method: "post", encType: "application/json" }
113+
);
114+
// will serialize into request.json() in your action
115+
// and will show up on useNavigation().json during the navigation
116+
117+
submit('{"key":"value"}', {
118+
method: "post",
119+
encType: "application/json",
120+
});
121+
// will encode into request.json() in your action
122+
// and will show up on useNavigation().json during the navigation
123+
```
124+
125+
Or plain text:
126+
127+
```tsx
128+
submit("value", { method: "post", encType: "text/plain" });
129+
// will serialize into request.text() in your action
130+
// and will show up on useNavigation().text during the navigation
131+
```
132+
81133
## Submit options
82134

83-
The second argument is a set of options that map directly to form submission attributes:
135+
The second argument is a set of options that map (mostly) directly to form submission attributes:
84136

85137
```tsx
86138
submit(null, {
87-
action: "/logout",
88139
method: "post",
140+
action: "/logout",
89141
});
90142

91143
// same as

docs/route/action.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ formData.get("lyrics");
101101

102102
For more information on `formData` see [Working with FormData][workingwithformdata].
103103

104+
### Opt-in serialization types
105+
106+
Note that when using [`useSubmit`][usesubmit] you may also pass `encType: "application/json"` or `encType: "text/plain"` to instead serialize your payload into `request.json()` or `request.text()`.
107+
104108
## Returning Responses
105109

106110
While you can return anything you want from an action and get access to it from [`useActionData`][useactiondata], you can also return a web [Response][response].
@@ -200,6 +204,7 @@ If a button name/value isn't right for your use case, you could also use a hidde
200204
[form]: ../components/form
201205
[workingwithformdata]: ../guides/form-data
202206
[useactiondata]: ../hooks/use-action-data
207+
[usesubmit]: ../hooks/use-submit
203208
[returningresponses]: ./loader#returning-responses
204209
[createbrowserrouter]: ../routers/create-browser-router
205210
[button]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button

docs/route/should-revalidate.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ interface ShouldRevalidateFunction {
6666
formAction?: Submission["formAction"];
6767
formEncType?: Submission["formEncType"];
6868
formData?: Submission["formData"];
69+
json?: Submission["json"];
70+
text?: Submission["text"];
6971
actionResult?: DataResult;
7072
defaultShouldRevalidate: boolean;
7173
}): boolean;

examples/auth/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import rollupReplace from "@rollup/plugin-replace";
55

66
// https://vitejs.dev/config/
77
export default defineConfig({
8+
server: {
9+
port: 3000,
10+
},
811
plugins: [
912
rollupReplace({
1013
preventAssignment: true,

examples/basic-data-router/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import rollupReplace from "@rollup/plugin-replace";
55

66
// https://vitejs.dev/config/
77
export default defineConfig({
8+
server: {
9+
port: 3000,
10+
},
811
plugins: [
912
rollupReplace({
1013
preventAssignment: true,

0 commit comments

Comments
 (0)