diff --git a/contributors.yml b/contributors.yml index 01178019f1..d8291ba57f 100644 --- a/contributors.yml +++ b/contributors.yml @@ -383,6 +383,7 @@ - sanketshah19 - sapphi-red - saul-atomrigs +- SAY-5 - sbolel - scarf005 - sealer3 diff --git a/docs/api/hooks/useFormAction.md b/docs/api/hooks/useFormAction.md index 7ffaf6711c..5c43bfe53f 100644 --- a/docs/api/hooks/useFormAction.md +++ b/docs/api/hooks/useFormAction.md @@ -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() { @@ -40,6 +40,12 @@ function SomeComponent() { } ``` +This hook adds a `basename` if your app specifies one, so that it +can be used with raw `
` elements in a progressively enhanced way. If +you are using this to provide an `action` to `` or `fetcher.submit`, you +will need to remove the `basename` since both of those will prepend it +internally. + ## Signature ```tsx diff --git a/docs/how-to/headers.md b/docs/how-to/headers.md index 5b5ee9ad48..c04c144080 100644 --- a/docs/how-to/headers.md +++ b/docs/how-to/headers.md @@ -9,9 +9,27 @@ title: HTTP Headers

+## 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"; @@ -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"; @@ -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. @@ -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 @@ -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. @@ -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`: @@ -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. diff --git a/packages/react-router/lib/dom/lib.tsx b/packages/react-router/lib/dom/lib.tsx index 9f6dde80bf..bb819cb9fc 100644 --- a/packages/react-router/lib/dom/lib.tsx +++ b/packages/react-router/lib/dom/lib.tsx @@ -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() { @@ -2638,6 +2638,14 @@ export function useSubmit(): SubmitFunction { * // closest route URL + "destroy" * let destroyAction = useFormAction("destroy"); * } + * ``` + * + * This hook adds a `basename` if your app specifies one, so that it + * can be used with raw `` elements in a progressively enhanced way. If + * you are using this to provide an `action` to `` or `fetcher.submit`, you + * will need to remove the `basename` since both of those will prepend it + * internally. + * * * @public * @category Hooks