Skip to content

Commit

Permalink
Support direct handlers in useSubmit/fetcher.submit/fetcher.load (#10362
Browse files Browse the repository at this point in the history
)
  • Loading branch information
brophdawg11 committed Apr 21, 2023
1 parent 3a7a7d9 commit 4357e37
Show file tree
Hide file tree
Showing 10 changed files with 813 additions and 70 deletions.
61 changes: 61 additions & 0 deletions .changeset/direct-handlers-router.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
"@remix-run/router": minor
---

- 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.

**Defining an `action` at the callsite:**

```jsx
let routes = [{ path: '/' }]; // No action on route

// Custom actions will behave as a submission navigation to the current location
router.navigate(null, {
formMethod "post",
formData: new FormData(),
action() {
// You may now define your custom action here
}
})
```

**Overriding an `action` at the call-site:**

```jsx
let routes = [{ path: '/', action: someAction }];
router.navigate(null, {
formMethod "post",
formData: new FormData(),
action() {
// This will be called instead of `someAction`
}
})
```

- 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.

**Fetching to a direct loader without a defined route:**

```jsx
let routes = [{ path: "/", action: someAction }];
// Note no location required
router.fetch("key", "0", null, {
loader() {
// Call this loader for the fetcher and avoid the need for a resource route
},
});
```

**Fetching to a direct action without a defined route:**

```jsx
let routes = [{ path: '/', action: someAction }];
// Note no location required
router.fetch("key", "0", null, {
formMethod "post",
formData: new FormData(),
action() {
// Call this action for the fetcher and avoid the need for a resource route
}
})
```
51 changes: 51 additions & 0 deletions .changeset/direct-handlers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
"react-router-dom": minor
---

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.

**`useSubmit:`**

```jsx
let router = createBrowserRouter([
{
path: "/",
Component() {
let submit = useSubmit();

submit(data, {
formMethod: "post",
encType: null,
action({ payload }) {
// You may now define your action here
},
});
},
},
]);
```

**`fetcher.load`/`fetcher.submit`:**

```jsx
let router = createBrowserRouter([
{
path: "/",
Component() {
let fetcher = useFetcher();

fetcher.load(() => {
// You may now define a loader here
});

fetcher.submit(data, {
formMethod: "post",
encType: null,
action({ payload }) {
// You may now define your action here
},
});
},
},
]);
```
22 changes: 22 additions & 0 deletions docs/hooks/use-fetcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ If you find yourself calling this function inside of click handlers, you can pro

<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>

### Direct `loader` specification

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`:

```tsx
fetcher.load(() => {
// Custom loader implementation here
});
```

## `fetcher.submit()`

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.
Expand Down Expand Up @@ -139,6 +149,18 @@ If you want to submit to an index route, use the [`?index` param][indexsearchpar

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

### Direct `action` specification

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`:

```tsx
fetcher.submit(data, {
action({ payload }) {
// Custom action implementation here
},
});
```

## `fetcher.data`

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.
Expand Down
14 changes: 13 additions & 1 deletion docs/hooks/use-submit.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function action({ request, payload }) {

## Submit options

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

```tsx
submit(null, {
Expand All @@ -136,4 +136,16 @@ submit(null, {
<Form action="/logout" method="post" />;
```

### Direct `action` specification

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`:

```tsx
submit(data, {
action({ request }) {
// Custom action implementation here
},
});
```

[pickingarouter]: ../routers/picking-a-router
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
},
"filesize": {
"packages/router/dist/router.umd.min.js": {
"none": "45 kB"
"none": "45.8 kB"
},
"packages/react-router/dist/react-router.production.min.js": {
"none": "13.3 kB"
Expand Down
Loading

0 comments on commit 4357e37

Please sign in to comment.