Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: remix-run/react-router
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6c0bbb14ed638a9adcae11376b084db450b69c84
Choose a base ref
...
head repository: remix-run/react-router
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 13fb25a51184f66192e023e2e18be5ff00f37827
Choose a head ref
Loading
Showing with 24,139 additions and 9,314 deletions.
  1. +43 −0 .github/workflows/deduplicate-yarn.yml
  2. +9 −2 .github/workflows/test.yml
  3. +12 −8 DEVELOPMENT.md
  4. +18 −0 contributors.yml
  5. +19 −0 docs/components/form.md
  6. +1 −1 docs/components/link.md
  7. +4 −16 docs/components/nav-link.md
  8. +46 −0 docs/fetch/redirectDocument.md
  9. +35 −1 docs/guides/api-development-strategy.md
  10. +4 −0 docs/guides/contributing.md
  11. +13 −0 docs/hooks/use-fetcher.md
  12. +58 −19 docs/hooks/use-navigate.md
  13. +10 −0 docs/hooks/use-navigation.md
  14. +2 −2 docs/hooks/use-outlet-context.md
  15. +63 −2 docs/hooks/use-submit.md
  16. +5 −0 docs/route/action.md
  17. +5 −1 docs/route/lazy.md
  18. +26 −19 docs/route/should-revalidate.md
  19. +36 −2 docs/router-components/browser-router.md
  20. +36 −2 docs/router-components/hash-router.md
  21. +33 −0 docs/router-components/memory-router.md
  22. +4 −0 docs/routers/create-browser-router.md
  23. +1 −1 docs/routers/picking-a-router.md
  24. +37 −0 docs/routers/router-provider.md
  25. +5 −0 examples/auth-router-provider/.gitignore
  26. +4 −0 examples/auth-router-provider/.stackblitzrc
  27. +28 −0 examples/auth-router-provider/README.md
  28. +12 −0 examples/auth-router-provider/index.html
  29. +1,475 −0 examples/auth-router-provider/package-lock.json
  30. +23 −0 examples/auth-router-provider/package.json
  31. +205 −0 examples/auth-router-provider/src/App.tsx
  32. +24 −0 examples/auth-router-provider/src/auth.ts
  33. +12 −0 examples/auth-router-provider/src/index.css
  34. +11 −0 examples/auth-router-provider/src/main.tsx
  35. +1 −0 examples/auth-router-provider/src/vite-env.d.ts
  36. +21 −0 examples/auth-router-provider/tsconfig.json
  37. +39 −0 examples/auth-router-provider/vite.config.ts
  38. +678 −298 examples/auth/package-lock.json
  39. +1 −1 examples/auth/package.json
  40. +3 −0 examples/auth/vite.config.ts
  41. +661 −218 examples/basic-data-router/package-lock.json
  42. +1 −1 examples/basic-data-router/package.json
  43. +3 −0 examples/basic-data-router/vite.config.ts
  44. +678 −298 examples/basic/package-lock.json
  45. +1 −1 examples/basic/package.json
  46. +3 −0 examples/basic/vite.config.ts
  47. +687 −305 examples/custom-filter-link/package-lock.json
  48. +1 −1 examples/custom-filter-link/package.json
  49. +3 −0 examples/custom-filter-link/vite.config.ts
  50. +678 −298 examples/custom-link/package-lock.json
  51. +1 −1 examples/custom-link/package.json
  52. +3 −0 examples/custom-link/vite.config.ts
  53. +680 −299 examples/custom-query-parsing/package-lock.json
  54. +1 −1 examples/custom-query-parsing/package.json
  55. +3 −0 examples/custom-query-parsing/vite.config.ts
  56. +661 −218 examples/data-router/package-lock.json
  57. +1 −1 examples/data-router/package.json
  58. +3 −0 examples/data-router/vite.config.ts
  59. +207 −191 examples/error-boundaries/package-lock.json
  60. +1 −1 examples/error-boundaries/package.json
  61. +3 −0 examples/error-boundaries/vite.config.ts
  62. +678 −301 examples/lazy-loading-router-provider/package-lock.json
  63. +1 −1 examples/lazy-loading-router-provider/package.json
  64. +3 −0 examples/lazy-loading-router-provider/vite.config.ts
  65. +678 −298 examples/lazy-loading/package-lock.json
  66. +1 −1 examples/lazy-loading/package.json
  67. +3 −0 examples/lazy-loading/vite.config.ts
  68. +5 −0 examples/modal-route-with-outlet/.gitignore
  69. +4 −0 examples/modal-route-with-outlet/.stackblitzrc
  70. +12 −0 examples/modal-route-with-outlet/README.md
  71. +12 −0 examples/modal-route-with-outlet/index.html
  72. +1,756 −0 examples/modal-route-with-outlet/package-lock.json
  73. +24 −0 examples/modal-route-with-outlet/package.json
  74. +172 −0 examples/modal-route-with-outlet/src/App.tsx
  75. +28 −0 examples/modal-route-with-outlet/src/images.ts
  76. +26 −0 examples/modal-route-with-outlet/src/index.css
  77. +14 −0 examples/modal-route-with-outlet/src/main.tsx
  78. +1 −0 examples/modal-route-with-outlet/src/vite-env.d.ts
  79. +21 −0 examples/modal-route-with-outlet/tsconfig.json
  80. +39 −0 examples/modal-route-with-outlet/vite.config.ts
  81. +715 −318 examples/modal/package-lock.json
  82. +1 −1 examples/modal/package.json
  83. +3 −0 examples/modal/vite.config.ts
  84. +1 −1 examples/multi-app/README.md
  85. +319 −339 examples/multi-app/package-lock.json
  86. +1 −1 examples/multi-app/package.json
  87. +3 −0 examples/multi-app/vite.config.js
  88. +661 −215 examples/navigation-blocking/package-lock.json
  89. +1 −1 examples/navigation-blocking/package.json
  90. +23 −6 examples/navigation-blocking/src/app.tsx
  91. +3 −0 examples/navigation-blocking/vite.config.ts
  92. +1 −1 examples/notes/README.md
  93. +669 −220 examples/notes/package-lock.json
  94. +1 −1 examples/notes/package.json
  95. +3 −0 examples/notes/vite.config.ts
  96. +678 −298 examples/route-objects/package-lock.json
  97. +1 −1 examples/route-objects/package.json
  98. +3 −0 examples/route-objects/vite.config.ts
  99. +663 −217 examples/scroll-restoration/package-lock.json
  100. +1 −1 examples/scroll-restoration/package.json
  101. +3 −0 examples/scroll-restoration/vite.config.ts
  102. +305 −355 examples/search-params/package-lock.json
  103. +1 −1 examples/search-params/package.json
  104. +3 −0 examples/search-params/vite.config.ts
  105. +702 −736 examples/ssr-data-router/package-lock.json
  106. +2 −2 examples/ssr-data-router/package.json
  107. +3 −0 examples/ssr-data-router/vite.config.js
  108. +951 −416 examples/ssr/package-lock.json
  109. +1 −1 examples/ssr/package.json
  110. +3 −0 examples/ssr/vite.config.js
  111. +49 −48 package.json
  112. +61 −0 packages/react-router-dom-v5-compat/CHANGELOG.md
  113. +68 −66 packages/react-router-dom-v5-compat/index.ts
  114. +9 −4 packages/react-router-dom-v5-compat/lib/components.tsx
  115. +3 −3 packages/react-router-dom-v5-compat/package.json
  116. +156 −0 packages/react-router-dom/CHANGELOG.md
  117. +26 −43 packages/react-router-dom/__tests__/concurrent-mode-navigations-test.tsx
  118. +128 −0 packages/react-router-dom/__tests__/data-browser-router-legacy-formdata-test.tsx
  119. +557 −72 packages/react-router-dom/__tests__/data-browser-router-test.tsx
  120. +163 −0 packages/react-router-dom/__tests__/data-static-router-test.tsx
  121. +1 −0 packages/react-router-dom/__tests__/exports-test.tsx
  122. +36 −0 packages/react-router-dom/__tests__/nav-link-active-test.tsx
  123. +8 −0 packages/react-router-dom/__tests__/polyfills/drop-FormData-submitter.ts
  124. +74 −0 packages/react-router-dom/__tests__/scroll-restoration-test.tsx
  125. +21 −0 packages/react-router-dom/__tests__/search-params-test.tsx
  126. +165 −0 packages/react-router-dom/__tests__/use-blocker-test.tsx
  127. +126 −0 packages/react-router-dom/__tests__/use-prompt-test.tsx
  128. +116 −76 packages/react-router-dom/dom.ts
  129. +229 −114 packages/react-router-dom/index.tsx
  130. +4 −4 packages/react-router-dom/package.json
  131. +16 −5 packages/react-router-dom/server.tsx
  132. +69 −0 packages/react-router-native/CHANGELOG.md
  133. +1 −0 packages/react-router-native/__tests__/exports-test.tsx
  134. +4 −0 packages/react-router-native/index.tsx
  135. +4 −4 packages/react-router-native/package.json
  136. +96 −0 packages/react-router/CHANGELOG.md
  137. +14 −301 packages/react-router/__tests__/data-memory-router-test.tsx
  138. +8 −0 packages/react-router/__tests__/generatePath-test.tsx
  139. +517 −216 packages/react-router/__tests__/navigate-test.tsx
  140. +2 −1 packages/react-router/__tests__/setup.ts
  141. +286 −0 packages/react-router/__tests__/use-revalidator-test.tsx
  142. +0 −1 packages/react-router/__tests__/useNavigate-test.tsx
  143. +44 −0 packages/react-router/__tests__/utils/MemoryNavigate.tsx
  144. +7 −0 packages/react-router/__tests__/utils/getHtml.ts
  145. +3 −0 packages/react-router/__tests__/utils/tick.ts
  146. +41 −31 packages/react-router/index.ts
  147. +54 −20 packages/react-router/lib/components.tsx
  148. +5 −5 packages/react-router/lib/context.ts
  149. +68 −39 packages/react-router/lib/hooks.tsx
  150. +3 −3 packages/react-router/package.json
  151. +97 −0 packages/router/CHANGELOG.md
  152. +20 −0 packages/router/__tests__/hash-test.ts
  153. +64 −0 packages/router/__tests__/router-memory-test.ts
  154. +1,426 −97 packages/router/__tests__/router-test.ts
  155. +2 −1 packages/router/__tests__/setup.ts
  156. +25 −0 packages/router/__tests__/utils/createDeferred.ts
  157. +19 −5 packages/router/history.ts
  158. +9 −4 packages/router/index.ts
  159. +2 −2 packages/router/package.json
  160. +634 −368 packages/router/router.ts
  161. +152 −55 packages/router/utils.ts
  162. +6 −6 ...hes/{@changesets+get-dependents-graph+1.3.3.patch → @changesets+get-dependents-graph+1.3.6.patch}
  163. +1,896 −1,778 yarn.lock
43 changes: 43 additions & 0 deletions .github/workflows/deduplicate-yarn.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: ⚙️ Deduplicate yarn.lock

on:
push:
branches:
- dev
paths:
- ./yarn.lock

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
format:
if: github.repository == 'remix-run/react-router'
runs-on: ubuntu-latest

steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3

- name: ⎔ Setup node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: "yarn"

- name: ⚙️ Dedupe yarn.lock
run: npx yarn-deduplicate && rm -rf ./node_modules && yarn

- name: 💪 Commit
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .
if [ -z "$(git status --porcelain)" ]; then
echo "💿 no deduplication needed"
exit 0
fi
git commit -m "chore: deduplicate `yarn.lock`"
git push
echo "💿 https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)"
11 changes: 9 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -21,7 +21,14 @@ concurrency:

jobs:
test:
name: 🧪 Test
name: "🧪 Test: (Node: ${{ matrix.node }})"
strategy:
fail-fast: false
matrix:
node:
- 16
- 18

runs-on: ubuntu-latest

steps:
@@ -33,7 +40,7 @@ jobs:
with:
cache: yarn
check-latest: true
node-version-file: ".nvmrc"
node-version: ${{ matrix.node }}

- name: Disable GitHub Actions Annotations
run: |
20 changes: 12 additions & 8 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

New releases should be created from release branches originating from the `dev` branch. When you are ready to begin the release process:

- Make sure you've pulled all of the changes from GitHub for both `dev` and `main` branches.
- Make sure you've pulled all the changes from GitHub for both `dev` and `main` branches.
- Check out the `dev` branch.
- Create a new release branch with the `release-` prefix (eg, `git checkout -b release-next`).
- **IMPORTANT:** The `release-` prefix is important, as this is what triggers our GitHub CI workflow that will ultimately publish the release.
@@ -17,7 +17,7 @@ Changesets will do most of the heavy lifting for our releases. When changes are

- Ensure you are on the new `release-*` branch.
- Enter Changesets pre-release mode using the `pre` tag: `yarn changeset pre enter pre`.
- Commit the change and push the the `release-*` branch to GitHub.
- Commit the change and push the `release-*` branch to GitHub.
- Wait for the release workflow to finish. The Changesets action in the workflow will open a PR that will increment all versions and generate the changelogs.
- Review the updated `CHANGELOG` files and make any adjustments necessary, then merge the PR into the `release-*` branch.
- `find packages -name 'CHANGELOG.md' -mindepth 2 -maxdepth 2 -exec code {} \;`
@@ -30,27 +30,31 @@ You may need to make changes to a pre-release prior to publishing a final stable
- Make whatever changes you need.
- Create a new changeset: `yarn changeset`.
- **IMPORTANT:** This is required even if you ultimately don't want to include these changes in the logs. Remember, changelogs can be edited prior to publishing, but the Changeset version script needs to see new changesets in order to create a new version.
- Commit the changesets and push the the `release-*` branch to GitHub.
- Commit the changesets and push the `release-*` branch to GitHub.
- Wait for the release workflow to finish and the Changesets action to open its PR that will increment all versions.
- Review the PR, make any adjustments necessary, and merge it into the `release-*` branch.
- Once the PR is merged, the release workflow will publish the updated packages to npm.

### Publishing the stable release

- Exit Changesets pre-release mode: `yarn changeset pre exit`.
- Commit the edited pre-release file along with any unpublished changesets, and push the the `release-*` branch to GitHub.
- Commit the edited pre-release file along with any unpublished changesets, and push the `release-*` branch to GitHub.
- Wait for the release workflow to finish. The Changesets action in the workflow will open a PR that will increment all versions and generate the changelogs for the stable release.
- Review the updated `CHANGELOG` files and make any adjustments necessary.
- `find packages -name 'CHANGELOG.md' -mindepth 2 -maxdepth 2 -exec code {} \;`
- We should remove the changelogs for all pre-releases ahead of publishing the stable version.
- [TODO: We should automate this]
- Prepare the github release notes
- Prepare the GitHub release notes
- Copy the relevant changelog entries from all packages into the Release Notes and adjust accordingly, matching the format used by prior releases
- Merge the PR into the `release-*` branch.
- Once the PR is merged, the release workflow will publish the updated packages to npm.
- Once the release is published:
- merge the `release-*` branch into `main` and push it up to GitHub
- merge the `release-*` branch into `dev` and push it up to GitHub
- Convert the `react-router@6.x.y` tag to a Release on Github with the name `v6.x.y`
- Pull the latest `release-*` branch containing the PR you just merged
- Merge the `release-*` branch into `main` **using a non-fast-forward merge** and push it up to GitHub
- `git checkout main; git merge --no-ff release-next`
- Merge the `release-*` branch into `dev` **using a non-fast-forward merge** and push it up to GitHub
- `git checkout dev; git merge --no-ff release-next`
- Convert the `react-router@6.x.y` tag to a Release on GitHub with the name `v6.x.y`

### Hotfix releases

18 changes: 18 additions & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
- 0xEddie
- abdallah-nour
- abeadam
- abhi-kr-2100
- AchThomas
- adamdotjs
- adil62
- adrienharnay
- afzalsayed96
- Ajayff4
- akamfoad
@@ -16,6 +18,8 @@
- andreiduca
- antonmontrezor
- appden
- arjunyel
- arka1002
- arnassavickas
- aroyan
- avipatel97
@@ -46,6 +50,7 @@
- cvbuelow
- damianstasik
- danielberndt
- daniilguit
- dauletbaev
- david-crespo
- decadentsavant
@@ -74,6 +79,7 @@
- GuptaSiddhant
- haivuw
- hernanif1
- holynewbie
- hongji00
- hsbtr
- hyesungoh
@@ -83,6 +89,7 @@
- infoxicator
- IsaiStormBlesed
- Isammoc
- istarkov
- ivanjeremic
- ivanjonas
- Ivanrenes
@@ -105,6 +112,7 @@
- jonkoops
- jrakotoharisoa
- kachun333
- juanpprieto
- kantuni
- kark
- KAROTT7
@@ -116,6 +124,7 @@
- koojaa
- KostiantynPopovych
- KutnerUri
- kylegirard
- landisdesign
- latin-1
- lequangdongg
@@ -124,6 +133,7 @@
- lopezac
- lordofthecactus
- LordThi
- louis-young
- loun4
- lounsbrough
- lpaube
@@ -139,6 +149,7 @@
- markivancho
- maruffahmed
- marvinruder
- mathpaquette
- matt-harro
- maxpou
- mcansh
@@ -155,6 +166,7 @@
- ms10596
- ned-park
- nilubisan
- Nismit
- nnhjs
- noisypigeon
- Obi-Dann
@@ -168,13 +180,16 @@
- petersendidit
- promet99
- pyitphyoaung
- refusado
- rimian
- robbtraister
- RobHannay
- rtmann
- rubeonline
- ryanflorence
- ryanhiebert
- sanketshah19
- sbolel
- scarf005
- senseibarni
- sergiodxa
@@ -184,10 +199,12 @@
- shivamsinghchahar
- SimenB
- SkayuX
- smithki
- souzasmatheus
- srmagura
- stasundr
- stmtk1
- swalker326
- tanayv
- theostavrides
- thisiskartik
@@ -204,6 +221,7 @@
- turansky
- tyankatsu0105
- underager
- valerii15298
- ValiantCat
- vijaypushkin
- vikingviolinist
19 changes: 19 additions & 0 deletions docs/components/form.md
Original file line number Diff line number Diff line change
@@ -215,6 +215,24 @@ See also:
- [`useActionData`][useactiondata]
- [`useSubmit`][usesubmit]

## `state`

The `state` property can be used to set a stateful value for the new location which is stored inside [history state][history-state]. This value can subsequently be accessed via `useLocation()`.

```tsx
<Form
method="post"
action="new-path"
state={{ some: "value" }}
/>
```

You can access this state value while on the "new-path" route:

```ts
let { state } = useLocation();
```

## `preventScrollReset`

If you are using [`<ScrollRestoration>`][scrollrestoration], this lets you prevent the scroll position from being reset to the top of the window when the form action redirects to a new location.
@@ -330,3 +348,4 @@ You can access those values from the `request.url`
[pickingarouter]: ../routers/picking-a-router
[scrollrestoration]: ./scroll-restoration
[link-preventscrollreset]: ./link#preventscrollreset
[history-state]: https://developer.mozilla.org/en-US/docs/Web/API/History/state
2 changes: 1 addition & 1 deletion docs/components/link.md
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ A relative `<Link to>` value (that does not begin with `/`) resolves relative to

## `relative`

By default, links are relative to the route hierarchy, so `..` will go up one `Route` level. Occasionally, you may find that you have matching URL patterns that do not make sense to be nested, and you'd prefer to use relative _path_ routing. You can opt into this behavior with `relative`:
By default, links are relative to the route hierarchy (`relative="route"`), so `..` will go up one `Route` level. Occasionally, you may find that you have matching URL patterns that do not make sense to be nested, and you'd prefer to use relative _path_ routing. You can opt into this behavior with `relative="path"`:

```jsx
// Contact and EditContact do not share additional UI layout
20 changes: 4 additions & 16 deletions docs/components/nav-link.md
Original file line number Diff line number Diff line change
@@ -84,29 +84,17 @@ You can pass a render prop as children to customize the content of the `<NavLink

The `end` prop changes the matching logic for the `active` and `pending` states to only match to the "end" of the NavLink's `to` path. If the URL is longer than `to`, it will no longer be considered active.

Without the end prop, this link is always active because every URL matches `/`.

```tsx
<NavLink to="/">Home</NavLink>
```

To match the URL "to the end" of `to`, use `end`:

```tsx
<NavLink to="/" end>
Home
</NavLink>
```

Now this link will only be active at `"/"`. This works for paths with more segments as well:

| Link | URL | isActive |
| ----------------------------- | ------------ | -------- |
| `<NavLink to="/tasks" />` | `/tasks` | true |
| `<NavLink to="/tasks" />` | `/tasks/123` | true |
| `<NavLink to="/tasks" end />` | `/tasks` | true |
| `<NavLink to="/tasks" end />` | `/tasks/123` | false |

**A note on links to the root route**

`<NavLink to="/">` is an exceptional case because _every_ URL matches `/`. To avoid this matching every single route by default, it effectively ignores the `end` prop and only matches when you're at the root route.

## `caseSensitive`

Adding the `caseSensitive` prop changes the matching logic to make it case sensitive.
46 changes: 46 additions & 0 deletions docs/fetch/redirectDocument.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: redirectDocument
new: true
---

# `redirectDocument`

This is a small wrapper around [`redirect`][redirect] that will trigger a document-level redirect to the new location instead of a client-side navigation.

This is most useful when you have a React Router app living next to a separate app on the same domain and need to redirect from the React Router app to the other app via `window.location` instead of a React Router navigation:

```jsx
import { redirectDocument } from "react-router-dom";

const loader = async () => {
const user = await getUser();
if (!user) {
return redirectDocument("/otherapp/login");
}
return null;
};
```

## Type Declaration

```ts
type RedirectFunction = (
url: string,
init?: number | ResponseInit
) => Response;
```

## `url`

The URL to redirect to.

```js
redirectDocument("/otherapp/login");
```

## `init`

The [Response][response] options to be used in the response.

[response]: https://developer.mozilla.org/en-US/docs/Web/API/Response/Response
[redirect]: ./redirect
Loading