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
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@
- sanketshah19
- sapphi-red
- saul-atomrigs
- SAY-5
- sbolel
- scarf005
- sealer3
Expand Down
8 changes: 7 additions & 1 deletion docs/api/hooks/useFormAction.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ the current URL of the app.
This is used internally by [`Form`](../components/Form) to resolve the `action` to the closest
route, but can be used generically as well.

```tsx
```ts
import { useFormAction } from "react-router";

function SomeComponent() {
Expand All @@ -40,6 +40,12 @@ function SomeComponent() {
}
```

<docs-info>This hook adds a `basename` if your app specifies one, so that it
can be used with raw `<form>` elements in a progressively enhanced way. If
you are using this to provide an `action` to `<Form>` or `fetcher.submit`, you
will need to remove the `basename` since both of those will prepend it
internally.</docs-info>

## Signature

```tsx
Expand Down
34 changes: 26 additions & 8 deletions docs/how-to/headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,27 @@ title: HTTP Headers
<br/>
<br/>

## Reading request headers

The `request` sent to route handlers is a standard Web Fetch [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request), so you can read headers directly from the [`request.headers`](https://developer.mozilla.org/en-US/docs/Web/API/Request/headers) property:

```tsx filename=some-route.tsx
export async function loader({
request,
}: Route.LoaderArgs) {
// Standard Headers methods are available
const userAgent = request.headers.get("User-Agent");
const hasCookies = request.headers.has("Cookie");

// ...
}
```

## Setting response headers

Headers are primarily defined with the route module `headers` export. You can also set headers in `entry.server.tsx`.

## From Route Modules
### From Route Modules

```tsx filename=some-route.tsx
import { Route } from "./+types/some-route";
Expand All @@ -28,11 +46,11 @@ export function headers(_: Route.HeadersArgs) {

You can return either a [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) instance or `HeadersInit`.

## From loaders and actions
### From loaders and actions

When the header is dependent on loader data, loaders and actions can also set headers.

### 1. Wrap your return value in `data`
**1. Wrap your return value in `data`**

```tsx lines=[1,8]
import { data } from "react-router";
Expand All @@ -50,7 +68,7 @@ export async function loader({ params }: LoaderArgs) {
}
```

### 2. Return from `headers` export
**2. Return from `headers` export**

Headers from loaders and actions are not sent automatically. You must explicitly return them from the `headers` export.

Expand All @@ -71,7 +89,7 @@ export function headers({

One notable exception is `Set-Cookie` headers, which are automatically preserved from `headers`, `loader`, and `action` in parent routes, even without exporting `headers` from the child route.

## Merging with parent headers
### Merging with parent headers

Consider these nested routes

Expand All @@ -85,7 +103,7 @@ If both route modules want to set headers, the headers from the deepest matching

When you need to keep both the parent and the child headers, you need to merge them in the child route.

### Appending
#### Appending

The easiest way is to simply append to the parent headers. This avoids overwriting a header the parent may have set and both are important.

Expand All @@ -98,7 +116,7 @@ export function headers({ parentHeaders }: HeadersArgs) {
}
```

### Setting
#### Setting

Sometimes it's important to overwrite the parent header. Do this with `set` instead of `append`:

Expand All @@ -114,7 +132,7 @@ export function headers({ parentHeaders }: HeadersArgs) {

You can avoid the need to merge headers by only defining headers in "leaf routes" (index routes and child routes without children) and not in parent routes.

## From `entry.server.tsx`
### From `entry.server.tsx`

The `handleRequest` export receives the headers from the route module as an argument. You can append global headers here.

Expand Down
10 changes: 9 additions & 1 deletion packages/react-router/lib/dom/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2628,7 +2628,7 @@ export function useSubmit(): SubmitFunction {
* This is used internally by {@link Form} to resolve the `action` to the closest
* route, but can be used generically as well.
*
* @example
* ```ts
* import { useFormAction } from "react-router";
*
* function SomeComponent() {
Expand All @@ -2638,6 +2638,14 @@ export function useSubmit(): SubmitFunction {
* // closest route URL + "destroy"
* let destroyAction = useFormAction("destroy");
* }
* ```
*
* <docs-info>This hook adds a `basename` if your app specifies one, so that it
* can be used with raw `<form>` elements in a progressively enhanced way. If
* you are using this to provide an `action` to `<Form>` or `fetcher.submit`, you
* will need to remove the `basename` since both of those will prepend it
* internally.</docs-info>
*
*
* @public
* @category Hooks
Expand Down