From 1fb5a6759b6a5d5dfff84b963726ffb03cdeab1b Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Wed, 8 May 2024 17:03:53 +0200 Subject: [PATCH 01/25] docs: fix typos (#11538) --- CHANGELOG.md | 4 ++-- contributors.yml | 1 + docs/components/form.md | 2 +- docs/hooks/use-navigate.md | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd3e0e023..592c94c202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -476,7 +476,7 @@ Date: 2023-10-16 #### View Transitions ๐Ÿš€ -We're excited to release experimental support for the the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) in React Router! You can now trigger navigational DOM updates to be wrapped in `document.startViewTransition` to enable CSS animated transitions on SPA navigations in your application. +We're excited to release experimental support for the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) in React Router! You can now trigger navigational DOM updates to be wrapped in `document.startViewTransition` to enable CSS animated transitions on SPA navigations in your application. The simplest approach to enabling a View Transition in your React Router app is via the new [``](https://reactrouter.com/components/link#unstable_viewtransition) prop. This will cause the navigation DOM update to be wrapped in `document.startViewTransition` which will enable transitions for the DOM update. Without any additional CSS styles, you'll get a basic cross-fade animation for your page. @@ -1031,7 +1031,7 @@ Support absolute URLs in ``. If the URL is for the current origin, it w - Fixes 2 separate issues for revalidating fetcher `shouldRevalidate` calls ([#9948](https://github.com/remix-run/react-router/pull/9948)) - The `shouldRevalidate` function was only being called for _explicit_ revalidation scenarios (after a mutation, manual `useRevalidator` call, or an `X-Remix-Revalidate` header used for cookie setting in Remix). It was not properly being called on _implicit_ revalidation scenarios that also apply to navigation `loader` revalidation, such as a change in search params or clicking a link for the page we're already on. It's now correctly called in those additional scenarios. - - The parameters being passed were incorrect and inconsistent with one another since the `current*`/`next*` parameters reflected the static `fetcher.load` URL (and thus were identical). Instead, they should have reflected the the navigation that triggered the revalidation (as the `form*` parameters did). These parameters now correctly reflect the triggering navigation. + - The parameters being passed were incorrect and inconsistent with one another since the `current*`/`next*` parameters reflected the static `fetcher.load` URL (and thus were identical). Instead, they should have reflected the navigation that triggered the revalidation (as the `form*` parameters did). These parameters now correctly reflect the triggering navigation. - Fix bug with search params removal via `useSearchParams` ([#9969](https://github.com/remix-run/react-router/pull/9969)) - Respect `preventScrollReset` on `` ([#9963](https://github.com/remix-run/react-router/pull/9963)) - Fix navigation for hash routers on manual URL changes ([#9980](https://github.com/remix-run/react-router/pull/9980)) diff --git a/contributors.yml b/contributors.yml index a2aab00d2e..f52afd54ec 100644 --- a/contributors.yml +++ b/contributors.yml @@ -190,6 +190,7 @@ - nnhjs - noisypigeon - Obi-Dann +- omahs - omar-moquete - p13i - parched diff --git a/docs/components/form.md b/docs/components/form.md index d5626d753a..b095b62634 100644 --- a/docs/components/form.md +++ b/docs/components/form.md @@ -92,7 +92,7 @@ function ProjectsPage() { ; ``` -If the the current URL is `"/projects/123"`, the form inside the child +If the current URL is `"/projects/123"`, the form inside the child route, `ProjectsPage`, will have a default action as you might expect: `"/projects/123"`. In this case, where the route is the deepest matching route, both `
` and plain HTML forms have the same result. But the form inside of `ProjectsLayout` will point to `"/projects"`, not the full URL. In other words, it points to the matching segment of the URL for the route in which the form is rendered. diff --git a/docs/hooks/use-navigate.md b/docs/hooks/use-navigate.md index 3a80fc692d..978d3bf173 100644 --- a/docs/hooks/use-navigate.md +++ b/docs/hooks/use-navigate.md @@ -93,7 +93,7 @@ function EditContact() { } ``` -Please note that `relative: "path"` only impacts the resolution of a relative path. It does not change the the "starting" location for that relative path resolution. This resolution is always relative to the current location in the Route hierarchy (i.e., the route `useNavigate` is called in). +Please note that `relative: "path"` only impacts the resolution of a relative path. It does not change the "starting" location for that relative path resolution. This resolution is always relative to the current location in the Route hierarchy (i.e., the route `useNavigate` is called in). If you wish to use path-relative routing against the current URL instead of the route hierarchy, you can do that with the current [`location`][use-location] and the `URL` constructor (note the trailing slash behavior): From bfe61136a6fc4e14fd067102065bad93725a8fb5 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Fri, 10 May 2024 14:58:48 -0400 Subject: [PATCH 02/25] Add nightly release workflow (#11550) --- .github/workflows/release-nightly.yml | 95 +++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 .github/workflows/release-nightly.yml diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml new file mode 100644 index 0000000000..a33fcd0796 --- /dev/null +++ b/.github/workflows/release-nightly.yml @@ -0,0 +1,95 @@ +name: ๐ŸŒ’ Nightly Release + +on: + workflow_dispatch: + schedule: + - cron: "0 7 * * *" # every day at 12AM PST + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CI: true + +jobs: + # HEADS UP! this "nightly" job will only ever run on the `main` branch due to + # it being a cron job, and the last commit on main will be what github shows + # as the trigger however in the checkout below we specify the `v7` branch, + # so all the scripts in this job will be ran from that, confusing i know, so + # in some cases we'll need to create multiple PRs when modifying nightly + # release processes + nightly: + name: ๐ŸŒ’ Nightly Release + if: github.repository == 'remix-run/react-router' + runs-on: ubuntu-latest + outputs: + # allows this to be used in the `comment` job below - will be undefined + # if there's no release necessary + NEXT_VERSION: ${{ steps.version.outputs.NEXT_VERSION }} + steps: + - name: โฌ‡๏ธ Checkout repo + uses: actions/checkout@v4 + with: + ref: v7 + # checkout using a custom token so that we can push later on + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: ๐Ÿ“ฆ Setup pnpm + uses: pnpm/action-setup@v3.0.0 + + - name: โŽ” Setup node + uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + cache: "pnpm" + + - name: ๐Ÿ“ฅ Install deps + run: pnpm install --frozen-lockfile + + - name: ๐Ÿ•ต๏ธ Check for changes + id: version + run: | + SHORT_SHA=$(git rev-parse --short HEAD) + + # get latest nightly tag + LATEST_NIGHTLY_TAG=$(git tag -l v0.0.0-nightly-\* --sort=-creatordate | head -n 1) + + # check if last commit to v7 starts with the nightly tag we're about + # to create (minus the date) + # if it is, we'll skip the nightly creation + # if not, we'll create a new nightly tag + if [[ ${LATEST_NIGHTLY_TAG} == v0.0.0-nightly-${SHORT_SHA}-* ]]; then + echo "๐Ÿ›‘ Latest nightly tag is the same as the latest commit sha, skipping nightly release" + else + # yyyyMMdd format (e.g. 20221207) + DATE=$(date '+%Y%m%d') + # v0.0.0-nightly-- + NEXT_VERSION=0.0.0-nightly-${SHORT_SHA}-${DATE} + # set output so it can be used in other jobs + echo "NEXT_VERSION=${NEXT_VERSION}" >> $GITHUB_OUTPUT + fi + + - name: โคด๏ธ Update version + if: steps.version.outputs.NEXT_VERSION + run: | + git config --local user.email "hello@remix.run" + git config --local user.name "Remix Run Bot" + git checkout -b nightly/${{ steps.version.outputs.NEXT_VERSION }} + pnpm run version ${{steps.version.outputs.NEXT_VERSION}} + git push origin --tags + + - name: ๐Ÿ— Build + if: steps.version.outputs.NEXT_VERSION + run: pnpm build + + - name: ๐Ÿ” Setup npm auth + if: steps.version.outputs.NEXT_VERSION + run: | + echo "registry=https://registry.npmjs.org" >> ~/.npmrc + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + + - name: ๐Ÿš€ Publish + if: steps.version.outputs.NEXT_VERSION + run: pnpm run publish From ef67804d309e26b21baeacf21ec176a09e652745 Mon Sep 17 00:00:00 2001 From: tony-sn <57897153+tony-sn@users.noreply.github.com> Date: Thu, 16 May 2024 11:09:20 +1000 Subject: [PATCH 03/25] doc: Update create-browser-router.md example snippet (#11557) --- contributors.yml | 1 + docs/routers/create-browser-router.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 398f8a82b5..f1ed567129 100644 --- a/contributors.yml +++ b/contributors.yml @@ -242,6 +242,7 @@ - tlinhart - tom-sherman - tomasr8 +- tony-sn - TooTallNate - triangularcube - trungpv1601 diff --git a/docs/routers/create-browser-router.md b/docs/routers/create-browser-router.md index 07bbe697db..5358acf9ef 100644 --- a/docs/routers/create-browser-router.md +++ b/docs/routers/create-browser-router.md @@ -271,7 +271,7 @@ let router = createBrowserRouter(routes, { Let's define a middleware on each route via `handle` and call middleware sequentially first, then call all loaders in parallel - providing any data made available via the middleware: ```ts -const routes [ +const routes = [ { id: "parent", path: "/parent", From 9d42655bc6eedd9a09d0c82c48406c8d9268260f Mon Sep 17 00:00:00 2001 From: Remix Run Bot Date: Thu, 16 May 2024 01:09:51 +0000 Subject: [PATCH 04/25] chore: format --- docs/routers/create-browser-router.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/routers/create-browser-router.md b/docs/routers/create-browser-router.md index 5358acf9ef..4d32882dbc 100644 --- a/docs/routers/create-browser-router.md +++ b/docs/routers/create-browser-router.md @@ -275,7 +275,9 @@ const routes = [ { id: "parent", path: "/parent", - loader({ request }, context) { /*...*/ }, + loader({ request }, context) { + /*...*/ + }, handle: { async middleware({ request }, context) { context.parent = "PARENT MIDDLEWARE"; @@ -285,7 +287,9 @@ const routes = [ { id: "child", path: "child", - loader({ request }, context) { /*...*/ }, + loader({ request }, context) { + /*...*/ + }, handle: { async middleware({ request }, context) { context.child = "CHILD MIDDLEWARE"; @@ -297,12 +301,19 @@ const routes = [ ]; let router = createBrowserRouter(routes, { - async unstable_dataStrategy({ request, params, matches }) { + async unstable_dataStrategy({ + request, + params, + matches, + }) { // Run middleware sequentially and let them add data to `context` let context = {}; for (const match of matches) { if (match.route.handle?.middleware) { - await match.route.handle.middleware({ request, params }, context); + await match.route.handle.middleware( + { request, params }, + context + ); } } From ddda0f09a31ef264ffd069062eebee38b8841d90 Mon Sep 17 00:00:00 2001 From: Robin van der Vleuten Date: Sat, 18 May 2024 00:41:27 +0200 Subject: [PATCH 05/25] docs: Replace `.` typo with `;` (#11561) --- contributors.yml | 1 + docs/routers/create-browser-router.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index f1ed567129..40599f6738 100644 --- a/contributors.yml +++ b/contributors.yml @@ -205,6 +205,7 @@ - rimian - robbtraister - RobHannay +- robinvdvleuten - rtmann - rubeonline - ryanflorence diff --git a/docs/routers/create-browser-router.md b/docs/routers/create-browser-router.md index 4d32882dbc..9f93ec6bcc 100644 --- a/docs/routers/create-browser-router.md +++ b/docs/routers/create-browser-router.md @@ -259,7 +259,7 @@ let router = createBrowserRouter(routes, { // Don't override anything - just resolve route.lazy + call loader let result = await match.resolve(); console.log(`Done processing route ${match.route.id}`); - return result. + return result; }) ) }, From 7759e8e2912eb69f6dd63b2906490831a2154cfd Mon Sep 17 00:00:00 2001 From: Remix Run Bot Date: Fri, 17 May 2024 22:41:58 +0000 Subject: [PATCH 06/25] chore: format --- docs/routers/create-browser-router.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/routers/create-browser-router.md b/docs/routers/create-browser-router.md index 9f93ec6bcc..75f582747c 100644 --- a/docs/routers/create-browser-router.md +++ b/docs/routers/create-browser-router.md @@ -258,10 +258,12 @@ let router = createBrowserRouter(routes, { console.log(`Processing route ${match.route.id}`); // Don't override anything - just resolve route.lazy + call loader let result = await match.resolve(); - console.log(`Done processing route ${match.route.id}`); + console.log( + `Done processing route ${match.route.id}` + ); return result; }) - ) + ); }, }); ``` From 0999f6f323f22db53bda6feefb985b54a4f7f016 Mon Sep 17 00:00:00 2001 From: Cole Nelson <37457808+ctnelson1997@users.noreply.github.com> Date: Mon, 27 May 2024 23:51:23 -0500 Subject: [PATCH 07/25] Clarify necessary dependencies in tutorial (#11593) --- contributors.yml | 1 + docs/start/tutorial.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 40599f6738..278940f93c 100644 --- a/contributors.yml +++ b/contributors.yml @@ -53,6 +53,7 @@ - christowiz - codeape2 - coryhouse +- ctnelson1997 - cvbuelow - damianstasik - danielberndt diff --git a/docs/start/tutorial.md b/docs/start/tutorial.md index a115a7d289..cdc0400673 100644 --- a/docs/start/tutorial.md +++ b/docs/start/tutorial.md @@ -25,7 +25,8 @@ We'll be using [Vite][vite] for our bundler and dev server for this tutorial. Yo npm create vite@latest name-of-your-project -- --template react # follow prompts cd -npm install react-router-dom localforage match-sorter sort-by +npm install react-router-dom # always need this! +npm install localforage match-sorter sort-by # only for this tutorial. npm run dev ``` From 84fa36ee1ed79a40dc4c713f7328ef0d7ac4982a Mon Sep 17 00:00:00 2001 From: Gianluca Esposito Date: Tue, 28 May 2024 16:23:51 +0200 Subject: [PATCH 08/25] docs: Update `create-browser-router.md` (#11595) * Update create-browser-router.md * Sign CLA --- contributors.yml | 1 + docs/routers/create-browser-router.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 278940f93c..bb6a7125af 100644 --- a/contributors.yml +++ b/contributors.yml @@ -82,6 +82,7 @@ - frontsideair - fyzhu - fz6m +- gesposito - gianlucca - gijo-varghese - goldins diff --git a/docs/routers/create-browser-router.md b/docs/routers/create-browser-router.md index 75f582747c..0734aa7175 100644 --- a/docs/routers/create-browser-router.md +++ b/docs/routers/create-browser-router.md @@ -339,7 +339,7 @@ let router = createBrowserRouter(routes, { It's also possible you don't even want to define a loader implementation at the route level. Maybe you want to just determine the routes and issue a single GraphQL request for all of your data? You can do that by setting your `route.loader=true` so it qualifies as "having a loader", and then store GQL fragments on `route.handle`: ```ts -const routes [ +const routes = [ { id: "parent", path: "/parent", From d87656245172c650059b1010edfc8d33bfcccab5 Mon Sep 17 00:00:00 2001 From: Remix Run Bot Date: Tue, 28 May 2024 14:24:31 +0000 Subject: [PATCH 09/25] chore: format --- docs/routers/create-browser-router.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/routers/create-browser-router.md b/docs/routers/create-browser-router.md index 0734aa7175..29458dc0ab 100644 --- a/docs/routers/create-browser-router.md +++ b/docs/routers/create-browser-router.md @@ -345,7 +345,11 @@ const routes = [ path: "/parent", loader: true, handle: { - gql: gql`fragment Parent on Whatever { parentField }` + gql: gql` + fragment Parent on Whatever { + parentField + } + `, }, children: [ { @@ -353,7 +357,11 @@ const routes = [ path: "child", loader: true, handle: { - gql: gql`fragment Child on Whatever { childField }` + gql: gql` + fragment Child on Whatever { + childField + } + `, }, }, ], From 1c2dedb8380098eda736a20cb7d0a231b4701b08 Mon Sep 17 00:00:00 2001 From: Ryan Florence Date: Thu, 30 May 2024 14:14:34 -0600 Subject: [PATCH 10/25] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9039ebac65..98067bd895 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -711,6 +711,8 @@ Date: 2023-06-14 `6.13.0` is really a patch release in spirit but comes with a SemVer minor bump since we added a new future flag. +#### v7_startTransition + The **tl;dr;** is that `6.13.0` is the same as [`6.12.0`](https://github.com/remix-run/react-router/releases/tag/react-router%406.12.0) bue we've moved the usage of `React.startTransition` behind an opt-in `future.v7_startTransition` [future flag](https://reactrouter.com/en/main/guides/api-development-strategy) because we found that there are applications in the wild that are currently using `Suspense` in ways that are incompatible with `React.startTransition`. Therefore, in `6.13.0` the default behavior will no longer leverage `React.startTransition`: From 28afc7471394f0fdabb0117c7c9ad2ac9907d3dc Mon Sep 17 00:00:00 2001 From: Gesit Date: Thu, 30 May 2024 22:31:45 +0200 Subject: [PATCH 11/25] docs: added useBlocker to the data apis (#11600) --- contributors.yml | 1 + docs/routers/picking-a-router.md | 1 + 2 files changed, 2 insertions(+) diff --git a/contributors.yml b/contributors.yml index bb6a7125af..4f1ea4c4f3 100644 --- a/contributors.yml +++ b/contributors.yml @@ -268,3 +268,4 @@ - yracnet - yuleicul - zheng-chuang +- Geist5000 diff --git a/docs/routers/picking-a-router.md b/docs/routers/picking-a-router.md index 92dfea59f5..2612c1e077 100644 --- a/docs/routers/picking-a-router.md +++ b/docs/routers/picking-a-router.md @@ -134,6 +134,7 @@ The following APIs are introduced in React Router 6.4 and will only work when us [useactiondata]: ../hooks/use-action-data [useasyncerror]: ../hooks/use-async-error [useasyncvalue]: ../hooks/use-async-value +[useblocker]: ../hooks/use-blocker [usefetcher]: ../hooks/use-fetcher [usefetchers]: ../hooks/use-fetchers [useloaderdata]: ../hooks/use-loader-data From 2ea1ac38dbeb5b55790a8d12f9de4b50e67328f6 Mon Sep 17 00:00:00 2001 From: "remix-cla-bot[bot]" <92060565+remix-cla-bot[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 20:31:48 +0000 Subject: [PATCH 12/25] chore: sort contributors list --- contributors.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 4f1ea4c4f3..2a15d5b016 100644 --- a/contributors.yml +++ b/contributors.yml @@ -82,6 +82,7 @@ - frontsideair - fyzhu - fz6m +- Geist5000 - gesposito - gianlucca - gijo-varghese @@ -268,4 +269,3 @@ - yracnet - yuleicul - zheng-chuang -- Geist5000 From b191557000588728ff94e8a16c96d7c7fa46634a Mon Sep 17 00:00:00 2001 From: Oleg <67059482+OlegDev1@users.noreply.github.com> Date: Thu, 30 May 2024 22:34:04 +0200 Subject: [PATCH 13/25] Fixed a typo in concepts.md (#11601) --- contributors.yml | 1 + docs/start/concepts.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 2a15d5b016..3e6cda3446 100644 --- a/contributors.yml +++ b/contributors.yml @@ -269,3 +269,4 @@ - yracnet - yuleicul - zheng-chuang +- OlegDev1 \ No newline at end of file diff --git a/docs/start/concepts.md b/docs/start/concepts.md index 2bffc74a04..efad4ca7e6 100644 --- a/docs/start/concepts.md +++ b/docs/start/concepts.md @@ -568,7 +568,7 @@ The `Outlet` component will always render the next match. That means `` a If the URL were `/contact-us`, the element tree would change to: ```jsx - + ``` Because the contact form is not under the main `` route. From dac9d78b455cd9685751eff63b31d13e0a575fa1 Mon Sep 17 00:00:00 2001 From: "remix-cla-bot[bot]" <92060565+remix-cla-bot[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 20:34:08 +0000 Subject: [PATCH 14/25] chore: sort contributors list --- contributors.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 3e6cda3446..2f7badbebe 100644 --- a/contributors.yml +++ b/contributors.yml @@ -193,6 +193,7 @@ - nnhjs - noisypigeon - Obi-Dann +- OlegDev1 - omahs - omar-moquete - p13i @@ -269,4 +270,3 @@ - yracnet - yuleicul - zheng-chuang -- OlegDev1 \ No newline at end of file From 12609521105d09ae13d33c560f5566c2e4438019 Mon Sep 17 00:00:00 2001 From: Ryan Florence Date: Thu, 30 May 2024 16:06:24 -0600 Subject: [PATCH 15/25] Update CHANGELOG.md --- CHANGELOG.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98067bd895..9ee30c5c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -864,14 +864,16 @@ You can also check out the docs [here](https://reactrouter.com/en/dev/guides/api ### Minor Changes -- The first future flag being introduced is `future.v7_normalizeFormMethod` which will normalize the exposed `useNavigation()/useFetcher()` `formMethod` fields as uppercase HTTP methods to align with the `fetch()` (and some Remix) behavior. ([#10207](https://github.com/remix-run/react-router/pull/10207)) - - - When `future.v7_normalizeFormMethod` is unspecified or set to `false` (default v6 behavior), - - `useNavigation().formMethod` is lowercase - - `useFetcher().formMethod` is lowercase - - When `future.v7_normalizeFormMethod === true`: - - `useNavigation().formMethod` is UPPERCASE - - `useFetcher().formMethod` is UPPERCASE +#### future.v7_normalizeFormMethod + +The first future flag being introduced is `future.v7_normalizeFormMethod` which will normalize the exposed `useNavigation()/useFetcher()` `formMethod` fields as uppercase HTTP methods to align with the `fetch()` (and some Remix) behavior. ([#10207](https://github.com/remix-run/react-router/pull/10207)) + +- When `future.v7_normalizeFormMethod` is unspecified or set to `false` (default v6 behavior), + - `useNavigation().formMethod` is lowercase + - `useFetcher().formMethod` is lowercase +- When `future.v7_normalizeFormMethod === true`: + - `useNavigation().formMethod` is UPPERCASE + - `useFetcher().formMethod` is UPPERCASE ### Patch Changes From c41d6ec18cf45052ca14469a230b3b7aeb86f6e5 Mon Sep 17 00:00:00 2001 From: Ryan Florence Date: Thu, 30 May 2024 16:55:13 -0600 Subject: [PATCH 16/25] add future flags guide (#11603) --- docs/guides/api-development-strategy.md | 107 ++----------- docs/upgrading/future.md | 201 ++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 91 deletions(-) create mode 100644 docs/upgrading/future.md diff --git a/docs/guides/api-development-strategy.md b/docs/guides/api-development-strategy.md index 13c25cfd85..6070ae2a9b 100644 --- a/docs/guides/api-development-strategy.md +++ b/docs/guides/api-development-strategy.md @@ -5,34 +5,33 @@ new: true # API Development Strategy -Let's cut to the chase - major version upgrades can be a _pain_. Especially for something as foundational to your application as the framework or router it's built on. For Remix and React Router, we want to do our best to give you the smoothest upgrade experience possible. +React Router is foundational to your application. We want to make sure that upgrading to new major versions is as smooth as possible while still allowing us to adjust and enhance the behavior and API as the React ecosystem advances. -This strategy is discussed in more detail in our [Future Flags][future-flags-blog-post] blog post, so give that a read if you want any more info at the end of this doc! +Our strategy and motivations are discussed in more detail in our [Future Flags][future-flags-blog-post] blog post. -## Goals +## Future Flags -Our goals for major Remix and React Router releases are: +When an API changes in a breaking way, it is introduced in a future flag. This allows you to opt-in to one change a time before it becomes the default in the next major version. -- Developers can opt-into SemVer-major features individually _as they are released_ instead of having to wait to adopt them all at once when a new major version hits NPM -- Having opted into features ahead-of-time, developers can upgrade to new major versions in a single short-lived branch/commit (hours, not weeks) +- Without enabling the future flag, nothing changes about your app +- Enabling the flag changes the behavior for that feature -## Implementation +All current future flags are documented in the [Future Flags Guide](../upgrading/future) to help you stay up-to-date. -We plan to do this via what we're calling **Future Flags** that you'll provide when you initialize your [Data Router][picking-a-router]. Think of these as **feature flags for future features**. As we implement new features, we always try to do them in a backwards-compatible way. But when a breaking change is warranted, we don't table that feature up for an _eventual_ v7 release. Instead, we add a **Future Flag** and implement the new feature alongside the current behavior in a v6 minor release. This allows users to start using the feature, providing feedback, and reporting bugs _immediately_. +## Unstable Flags -That way, not only can you adopt features incrementally (and eagerly without a major version bump), we can also work out any kinks incrementally _before_ releasing v7. Eventually we also then add deprecation warnings to the v6 releases to nudge users to the new behavior. Then in v7 we remove the old v6 approach, remove the deprecations, and remove the flag - thus making the flagged behavior the new default in v7. If at the time v6 is released, an application has opted into _all_ future flags and updated their code - then they should just be able to update their dependency to v7, delete the future flags, and be running on v7 in a matter of minutes. +Unstable flags are for features still being designed and developed and made available to our users to help us get it right. -## Unstable vs. V7 Flags +Unstable flags are not recommended for production: -Future flags come in 2 forms: +- they will change without warning and without upgrade paths +- they will have bugs +- they aren't documented +- they may be scrapped completely -**`future.unstable_feature`** +When you opt-in to an unstable flag you are becoming a contributor to the project, rather than a user. We appreciate your help, but please be aware of the new role! -`unstable_` flags allow us to iterate on the API with early adopters as if we're in `v0.x.x` versions, but for a specific feature. This avoids churning the API for all users and arriving at better APIs in the final release. This _does not mean_ that we think the feature is bug-ridden! We _absolutely_ want early adopters to start using these features so we can iterate on (and/or gain confidence in) the API. - -**`future.v7_feature`** - -`v7_` indicates a breaking change from v6 behavior and implies (1) that the API is considered stable and will not under any more breaking changes and (2) that the API will become the default behavior in v7. A `v7_` flag _does not_ mean the feature is bug-free - no software is! Our recommendation is to upgrade to v7 flags as you have the time, as it will make your v7 upgrade _much_ smoother. +To learn about current unstable flags, keep an eye on the [CHANGELOG](../start/changelog). ### Example New Feature Flow @@ -40,80 +39,6 @@ The decision flow for a new feature looks something like this (note this diagram ![Flowchart of the decision process for how to introduce a new feature][feature-flowchart] -The lifecycle is thus either: - -- Non-Breaking + Stable API Feature -> Lands in v6 -- Non-Breaking + Unstable API -> `future.unstable_` flag -> Lands in v6 -- Breaking + Stable API Feature -> `future.v7_` flag -> Lands in v7 -- Breaking + Unstable API -> `future.unstable_` flag -> `future.v7_` flag -> Lands in v7 - -## Current Future Flags - -Here's the current future flags in React Router v6 today. - -### `@remix-run/router` Future Flags - -These flags are only applicable when using a [Data Router][picking-a-router] and are passed when creating the `router` instance: - -```js -const router = createBrowserRouter(routes, { - future: { - v7_normalizeFormMethod: true, - }, -}); -``` - -| Flag | Description | -| ------------------------------------------- | --------------------------------------------------------------------- | -| `v7_fetcherPersist` | Delay active fetcher cleanup until they return to an `idle` state | -| `v7_normalizeFormMethod` | Normalize `useNavigation().formMethod` to be an uppercase HTTP Method | -| [`v7_partialHydration`][partialhydration] | Support partial hydration for Server-rendered apps | -| `v7_prependBasename` | Prepend the router basename to navigate/fetch paths | -| [`v7_relativeSplatPath`][relativesplatpath] | Fix buggy relative path resolution in splat routes | - -#### `createStaticHandler` Future Flags - -These flags are only applicable when [SSR][ssr]-ing a React Router app: - -```js -const handler = createStaticHandler(routes, { - future: { - v7_throwAbortReason: true, - }, -}); -``` - -| Flag | Description | -| ------------------------------------------- | ----------------------------------------------------------------------- | -| [`v7_relativeSplatPath`][relativesplatpath] | Fix buggy relative path resolution in splat routes | -| [`v7_throwAbortReason`][abortreason] | Throw `request.signal.reason` if a `query`/`queryRoute` call is aborted | - -### React Router Future Flags - -These flags apply to both Data and non-Data Routers and are passed to the rendered React component: - -```jsx - - {/*...*/} - -``` - -```jsx - -``` - -| Flag | Description | -| -------------------- | --------------------------------------------------------------------------- | -| `v7_startTransition` | Wrap all router state updates in [`React.startTransition`][starttransition] | - [future-flags-blog-post]: https://remix.run/blog/future-flags [feature-flowchart]: https://remix.run/docs-images/feature-flowchart.png [picking-a-router]: ../routers/picking-a-router -[starttransition]: https://react.dev/reference/react/startTransition -[partialhydration]: ../routers/create-browser-router#partial-hydration-data -[relativesplatpath]: ../hooks/use-resolved-path#splat-paths -[ssr]: ../guides/ssr -[abortreason]: ../routers/create-static-handler#handlerqueryrequest-opts diff --git a/docs/upgrading/future.md b/docs/upgrading/future.md new file mode 100644 index 0000000000..ffbf636994 --- /dev/null +++ b/docs/upgrading/future.md @@ -0,0 +1,201 @@ +--- +title: Current Future Flags +order: 1 +new: true +--- + +# Future Flags + +The following future flags are stable and ready to adopt. To read more about future flags see [Development Strategy](../guides/api-development-strategy) + +## Update to latest v6.x + +First update to the latest minor version of v6.x to have the latest future flags. + +๐Ÿ‘‰ **Update to latest v6** + +```shellscript nonumber +npm install react-router-dom@6 +``` + +## v7_relativeSplatPath + +**Background** + +Changes the relative path matching and linking for multi-segment splats paths like `dashboard/*` (vs. just `*`). [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md#minor-changes-2) for more information. + +๐Ÿ‘‰ **Enable the flag** + +Enabling the flag depends on the type of router: + +```tsx + +``` + +```tsx +createBrowserRouter(routes, { + future: { + v7_relativeSplatPath: true, + }, +}); +``` + +**Update your Code** + +If you have any routes with a path + a splat like `` and has relative links like `` or `` beneath it, you will need to update your code. + +๐Ÿ‘‰ **Split the `` into two** + +Split any multi-segment splat `` into a parent route with the path and a child route with the splat: + +```diff + + } /> +- } /> ++ ++ } /> ++ + + +// or +createBrowserRouter([ + { path: "/", element: }, + { +- path: "dashboard/*", +- element: , ++ path: "dashboard", ++ children: [{ path: "*", element: }], + }, +]); +``` + +๐Ÿ‘‰ **Update relative links** + +Update any `` elements within that route tree to include the extra `..` relative segment to continue linking to the same place: + +```diff +function Dashboard() { + return ( +
+

Dashboard

+ + + + } /> + } /> + } + /> + +
+ ); +} +``` + +## v7_startTransition + +**Background** + +This uses `React.useTransition` instead of `React.useState` for Router state updates. View the [CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7_starttransition) for more information. + +๐Ÿ‘‰ **Enable the flag** + +```tsx + + +// or + +``` + +๐Ÿ‘‰ **Update your Code** + +You don't need to update anything unless you are using `React.lazy` _inside_ of a component. + +Using `React.lazy` inside of a component is incompatible with `React.useTransition` (or other code that makes promises inside of components). Move `React.lazy` to the module scope and stop making promises inside of components. This is not a limitation of React Router but rather incorrect usage of React. + +## v7_fetcherPersist + +If you are not using a `createBrowserRouter` you can skip this + +**Background** + +The fetcher lifecycle is now based on when it returns to an idle state rather than when its owner component unmounts: [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#persistence-future-flag-futurev7_fetcherpersist) for more information. + +**Enable the Flag** + +```tsx +createBrowserRouter(routes, { + future: { + v7_fetcherPersist: true, + }, +}); +``` + +**Update your Code** + +It's unlikely to affect your app. You may want to check any usage of `useFetchers` as they may persist longer than they did before. Depending on what you're doing, you may render something longer than before. + +## v7_normalizeFormMethod + +If you are not using a `createBrowserRouter` you can skip this + +This normalizes `formMethod` fields as uppercase HTTP methods to align with the `fetch()` behavior. [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#futurev7_normalizeformmethod) for more information. + +๐Ÿ‘‰ **Enable the Flag** + +```tsx +createBrowserRouter(routes, { + future: { + v7_normalizeFormMethod: true, + }, +}); +``` + +**Update your Code** + +If any of your code is checking for lowercase HTTP methods, you will need to update it to check for uppercase HTTP methods (or call `toLowerCase()` on it). + +๐Ÿ‘‰ **Compare `formMethod` to UPPERCASE** + +```diff +-useNavigation().formMethod === "post" +-useFetcher().formMethod === "get"; ++useNavigation().formMethod === "POST" ++useFetcher().formMethod === "GET"; +``` + +## v7_partialHydration + +If you are not using a `createBrowserRouter` you can skip this + +This allows SSR frameworks to provide only partial hydration data. It's unlikely you need to worry about this, just turn the flag on. [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#partial-hydration) for more information. + +๐Ÿ‘‰ **Enable the Flag** + +```tsx +createBrowserRouter(routes, { + future: { + v7_partialHydration: true, + }, +}); +``` From 2841936b7ef972e14aeb442f7f4fe1bb0a524a52 Mon Sep 17 00:00:00 2001 From: Arman Date: Sun, 2 Jun 2024 05:44:13 +0300 Subject: [PATCH 17/25] fix diff highlight (#11605) --- contributors.yml | 1 + docs/start/overview.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index 2f7badbebe..a1d22ba7be 100644 --- a/contributors.yml +++ b/contributors.yml @@ -23,6 +23,7 @@ - arjunyel - arka1002 - arnassavickas +- Armanio - aroyan - ashusnapx - avipatel97 diff --git a/docs/start/overview.md b/docs/start/overview.md index 6af2e9573a..67f44c0dc7 100644 --- a/docs/start/overview.md +++ b/docs/start/overview.md @@ -383,7 +383,7 @@ See: Instead of waiting for the data for the next page, you can [`defer`][defer] data so the UI flips over to the next screen with placeholder UI immediately while the data loads. -```jsx lines=[12,22-29,32-35,42] +```jsx lines=[12,22-29,32-35] } From f2402637ab8139885009f72776120d085c83da8e Mon Sep 17 00:00:00 2001 From: "remix-cla-bot[bot]" <92060565+remix-cla-bot[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 02:44:17 +0000 Subject: [PATCH 18/25] chore: sort contributors list --- contributors.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributors.yml b/contributors.yml index a1d22ba7be..2c78f133b8 100644 --- a/contributors.yml +++ b/contributors.yml @@ -22,8 +22,8 @@ - appden - arjunyel - arka1002 -- arnassavickas - Armanio +- arnassavickas - aroyan - ashusnapx - avipatel97 From 44fa9aa53ff4ec6fdca5b6919e09a2c94a0f0d81 Mon Sep 17 00:00:00 2001 From: Gaspard Bucher Date: Sun, 2 Jun 2024 04:45:30 +0200 Subject: [PATCH 19/25] Small typos and fixes to the tutorial (#11598) Co-authored-by: Tim Dorr --- contributors.yml | 1 + docs/start/tutorial.md | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/contributors.yml b/contributors.yml index 2c78f133b8..a7e93bbec6 100644 --- a/contributors.yml +++ b/contributors.yml @@ -83,6 +83,7 @@ - frontsideair - fyzhu - fz6m +- gaspard - Geist5000 - gesposito - gianlucca diff --git a/docs/start/tutorial.md b/docs/start/tutorial.md index cdc0400673..929557d754 100644 --- a/docs/start/tutorial.md +++ b/docs/start/tutorial.md @@ -271,7 +271,7 @@ export default function Contact() { const contact = { first: "Your", last: "Name", - avatar: "https://placekitten.com/g/200/200", + avatar: "https://robohash.org/you.png?size=200x200", twitter: "your_handle", notes: "Some notes", favorite: true, @@ -282,7 +282,7 @@ export default function Contact() {
@@ -337,8 +337,7 @@ export default function Contact() { } function Favorite({ contact }) { - // yes, this is a `let` for later - let favorite = contact.favorite; + const favorite = contact.favorite; return (