Skip to content

Commit 4357e37

Browse files
authored
Support direct handlers in useSubmit/fetcher.submit/fetcher.load (#10362)
1 parent 3a7a7d9 commit 4357e37

File tree

10 files changed

+813
-70
lines changed

10 files changed

+813
-70
lines changed

.changeset/direct-handlers-router.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
"@remix-run/router": minor
3+
---
4+
5+
- Add support for direct `action` functions to be passed to `router.navigate`. This allows you to skip the creation of a new route to handle the `action` , or you can also override the defined route `action` at the call-site.
6+
7+
**Defining an `action` at the callsite:**
8+
9+
```jsx
10+
let routes = [{ path: '/' }]; // No action on route
11+
12+
// Custom actions will behave as a submission navigation to the current location
13+
router.navigate(null, {
14+
formMethod "post",
15+
formData: new FormData(),
16+
action() {
17+
// You may now define your custom action here
18+
}
19+
})
20+
```
21+
22+
**Overriding an `action` at the call-site:**
23+
24+
```jsx
25+
let routes = [{ path: '/', action: someAction }];
26+
router.navigate(null, {
27+
formMethod "post",
28+
formData: new FormData(),
29+
action() {
30+
// This will be called instead of `someAction`
31+
}
32+
})
33+
```
34+
35+
- Add support for direct `action`/`loader` functions to be passed to `router.fetch`. This allows you to skip the creation of a new route to handle the `loader` or `action`, or you can also override the defined route `loader` or `action` at the call-site.
36+
37+
**Fetching to a direct loader without a defined route:**
38+
39+
```jsx
40+
let routes = [{ path: "/", action: someAction }];
41+
// Note no location required
42+
router.fetch("key", "0", null, {
43+
loader() {
44+
// Call this loader for the fetcher and avoid the need for a resource route
45+
},
46+
});
47+
```
48+
49+
**Fetching to a direct action without a defined route:**
50+
51+
```jsx
52+
let routes = [{ path: '/', action: someAction }];
53+
// Note no location required
54+
router.fetch("key", "0", null, {
55+
formMethod "post",
56+
formData: new FormData(),
57+
action() {
58+
// Call this action for the fetcher and avoid the need for a resource route
59+
}
60+
})
61+
```

.changeset/direct-handlers.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
"react-router-dom": minor
3+
---
4+
5+
Add direct `action` function support to `useSubmit`/`fetcher.submit` and direct `loader` support to `fetcher.load`. This allows you to skip the creation of a new route to handle the `action` or `loader`. If both a call-site handler and a route-defined handler exist, the call-site handler will be used.
6+
7+
**`useSubmit:`**
8+
9+
```jsx
10+
let router = createBrowserRouter([
11+
{
12+
path: "/",
13+
Component() {
14+
let submit = useSubmit();
15+
16+
submit(data, {
17+
formMethod: "post",
18+
encType: null,
19+
action({ payload }) {
20+
// You may now define your action here
21+
},
22+
});
23+
},
24+
},
25+
]);
26+
```
27+
28+
**`fetcher.load`/`fetcher.submit`:**
29+
30+
```jsx
31+
let router = createBrowserRouter([
32+
{
33+
path: "/",
34+
Component() {
35+
let fetcher = useFetcher();
36+
37+
fetcher.load(() => {
38+
// You may now define a loader here
39+
});
40+
41+
fetcher.submit(data, {
42+
formMethod: "post",
43+
encType: null,
44+
action({ payload }) {
45+
// You may now define your action here
46+
},
47+
});
48+
},
49+
},
50+
]);
51+
```

docs/hooks/use-fetcher.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ If you find yourself calling this function inside of click handlers, you can pro
108108

109109
<docs-info>Any `fetcher.load` calls that are active on the page will be re-executed as part of revalidation (either after a navigation submission, another fetcher submission, or a `useRevalidator()` call)</docs-info>
110110

111+
### Direct `loader` specification
112+
113+
If you want to perform a `fetcher.load`, but you don't want/need to create a route for your `loader`, you can pass a `loader` directly to `fetcher.load`:
114+
115+
```tsx
116+
fetcher.load(() => {
117+
// Custom loader implementation here
118+
});
119+
```
120+
111121
## `fetcher.submit()`
112122

113123
The imperative version of `<fetcher.Form>`. If a user interaction should initiate the fetch, you should use `<fetcher.Form>`. But if you, the programmer are initiating the fetch (not in response to a user clicking a button, etc.), then use this function.
@@ -139,6 +149,18 @@ If you want to submit to an index route, use the [`?index` param][indexsearchpar
139149

140150
If you find yourself calling this function inside of click handlers, you can probably simplify your code by using `<fetcher.Form>` instead.
141151

152+
### Direct `action` specification
153+
154+
If you want to perform a `fetcher.submit`, but you don't want/need to create a route for your `action`, you can pass an `action` directly to `fetcher.submit`:
155+
156+
```tsx
157+
fetcher.submit(data, {
158+
action({ payload }) {
159+
// Custom action implementation here
160+
},
161+
});
162+
```
163+
142164
## `fetcher.data`
143165

144166
The returned data from the loader or action is stored here. Once the data is set, it persists on the fetcher even through reloads and resubmissions.

docs/hooks/use-submit.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function action({ request, payload }) {
124124

125125
## Submit options
126126

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

129129
```tsx
130130
submit(null, {
@@ -136,4 +136,16 @@ submit(null, {
136136
<Form action="/logout" method="post" />;
137137
```
138138

139+
### Direct `action` specification
140+
141+
If you want to perform a submission, but you don't want/need to create a route for your `action`, you can pass an `action` to `useSubmit` which will perform a submission navigation to the current location but will use the provided `action`:
142+
143+
```tsx
144+
submit(data, {
145+
action({ request }) {
146+
// Custom action implementation here
147+
},
148+
});
149+
```
150+
139151
[pickingarouter]: ../routers/picking-a-router

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
},
106106
"filesize": {
107107
"packages/router/dist/router.umd.min.js": {
108-
"none": "45 kB"
108+
"none": "45.8 kB"
109109
},
110110
"packages/react-router/dist/react-router.production.min.js": {
111111
"none": "13.3 kB"

0 commit comments

Comments
 (0)