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
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
18 changes: 16 additions & 2 deletions docs/hooks/use-submit.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ You may also choose which type of serialization you'd like via the `encType` opt

```tsx
let obj = { key: "value" };
submit(obj, { encType: 'application/x-www-form-urlencoded' }); // -> request.formData()
submit(obj, {
encType: "application/x-www-form-urlencoded",
}); // -> request.formData()
```

```tsx
Expand Down Expand Up @@ -122,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 @@ -134,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