Skip to content

Releases: remix-run/react-router

v6.19.0

16 Nov 14:48
dcf0c2a
Compare
Choose a tag to compare

v6.18.0

31 Oct 14:28
667f936
Compare
Choose a tag to compare

Minor Changes

New Fetcher APIs

Per this RFC, we've introduced some new APIs that give you more granular control over your fetcher behaviors. (#10960)

  • You may now specify your own fetcher identifier via useFetcher({ key: string }), which allows you to access the same fetcher instance from different components in your application without prop-drilling
  • Fetcher keys are now exposed on the fetchers returned from useFetchers so that they can be looked up by key
  • Form and useSumbit now support optional navigate/fetcherKey props/params to allow kicking off a fetcher submission under the hood with an optionally user-specified key
    • <Form method="post" navigate={false} fetcherKey="my-key">
    • submit(data, { method: "post", navigate: false, fetcherKey: "my-key" })
    • Invoking a fetcher in this way is ephemeral and stateless
    • If you need to access the state of one of these fetchers, you will need to leverage useFetchers() or useFetcher({ key }) to look it up elsewhere

Persistence Future Flag (future.v7_fetcherPersist)

Per the same RFC as above, we've introduced a new future.v7_fetcherPersist flag that allows you to opt-into the new fetcher persistence/cleanup behavior. Instead of being immediately cleaned up on unmount, fetchers will persist until they return to an idle state. This makes pending/optimistic UI much easier in scenarios where the originating fetcher needs to unmount. (#10962)

  • This is sort of a long-standing bug fix as the useFetchers() API was always supposed to only reflect in-flight fetcher information for pending/optimistic UI -- it was not intended to reflect fetcher data or hang onto fetchers after they returned to an idle state
  • Keep an eye out for the following specific behavioral changes when opting into this flag and check your app for compatibility:
    • Fetchers that complete while still mounted will no longer appear in useFetchers() after completion - they served no purpose in there since you can access the data via useFetcher().data
    • Fetchers that previously unmounted while in-flight will not be immediately aborted and will instead be cleaned up once they return to an idle state
      • They will remain exposed via useFetchers while in-flight so you can still access pending/optimistic data after unmount
      • If a fetcher is no longer mounted when it completes, then it's result will not be post processed - e.g., redirects will not be followed and errors will not bubble up in the UI
      • However, if a fetcher was re-mounted elsewhere in the tree using the same key, then it's result will be processed, even if the originating fetcher was unmounted

Other Minor Changes

  • Add support for optional path segments in matchPath (#10768)

Patch Changes

  • Fix the future prop on BrowserRouter, HashRouter and MemoryRouter so that it accepts a Partial<FutureConfig> instead of requiring all flags to be included (#10962)
  • Fix router.getFetcher/router.deleteFetcher type definitions which incorrectly specified key as an optional parameter (#10960)

Full Changelog: 6.17.0...6.18.0

v6.17.0

16 Oct 15:56
edd9ad4
Compare
Choose a tag to compare

Minor Changes

View Transitions πŸš€

We're excited to release experimental support for the the View Transitions API 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. (#10916)

The simplest approach to enabling a View Transition in your React Router app is via the new <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.

If you need to apply more fine-grained styles for your animations, you can leverage the unstable_useViewTransitionState hook which will tell you when a transition is in progress and you can use that to apply classes or styles:

function ImageLink(to, src, alt) {
  const isTransitioning = unstable_useViewTransitionState(to);
  return (
    <Link to={to} unstable_viewTransition>
      <img
        src={src}
        alt={alt}
        style={{
          viewTransitionName: isTransitioning ? "image-expand" : "",
        }}
      />
    </Link>
  );
}

You can also use the <NavLink unstable_viewTransition> shorthand which will manage the hook usage for you and automatically add a transitioning class to the <a> during the transition:

a.transitioning img {
  view-transition-name: "image-expand";
}
<NavLink to={to} unstable_viewTransition>
  <img src={src} alt={alt} />
</NavLink>

For an example usage of View Transitions, check out our fork of the awesome Astro Records demo.

For more information on using the View Transitions API, please refer to the Smooth and simple transitions with the View Transitions API guide from the Google Chrome team.

Patch Changes

  • Log a warning and fail gracefully in ScrollRestoration when sessionStorage is unavailable (#10848)
  • Fix RouterProvider future prop type to be a Partial<FutureConfig> so that not all flags must be specified (#10900)
  • Allow 404 detection to leverage root route error boundary if path contains a URL segment (#10852)
  • Fix ErrorResponse type to avoid leaking internal field (#10876)

Full Changelog: 6.16.0...6.17.0

v6.16.0

13 Sep 16:38
13fb25a
Compare
Choose a tag to compare

Minor Changes

  • In order to move towards stricter TypeScript support in the future, we're aiming to replace current usages of any with unknown on exposed typings for user-provided data. To do this in Remix v2 without introducing breaking changes in React Router v6, we have added generics to a number of shared types. These continue to default to any in React Router and are overridden with unknown in Remix. In React Router v7 we plan to move these to unknown as a breaking change. (#10843)
    • Location now accepts a generic for the location.state value
    • ActionFunctionArgs/ActionFunction/LoaderFunctionArgs/LoaderFunction now accept a generic for the context parameter (only used in SSR usages via createStaticHandler)
    • The return type of useMatches (now exported as UIMatch) accepts generics for match.data and match.handle - both of which were already set to unknown
  • Move the @private class export ErrorResponse to an UNSAFE_ErrorResponseImpl export since it is an implementation detail and there should be no construction of ErrorResponse instances in userland. This frees us up to export a type ErrorResponse which correlates to an instance of the class via InstanceType. Userland code should only ever be using ErrorResponse as a type and should be type-narrowing via isRouteErrorResponse. (#10811)
  • Export ShouldRevalidateFunctionArgs interface (#10797)
  • Removed private/internal APIs only required for the Remix v1 backwards compatibility layer and no longer needed in Remix v2 (_isFetchActionRedirect, _hasFetcherDoneAnything) (#10715)

Patch Changes

  • Properly encode rendered URIs in server rendering to avoid hydration errors (#10769)
  • Add method/url to error message on aborted query/queryRoute calls (#10793)
  • Fix a race-condition with loader/action-thrown errors on route.lazy routes (#10778)
  • Fix type for actionResult on the arguments object passed to shouldRevalidate (#10779)

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.16.0

v6.15.0

10 Aug 14:57
e79cb77
Compare
Choose a tag to compare

Minor Changes

  • Add's a new redirectDocument() function which allows users to specify that a redirect from a loader/action should trigger a document reload (via window.location) instead of attempting to navigate to the redirected location via React Router (#10705)

Patch Changes

  • Ensure useRevalidator is referentially stable across re-renders if revalidations are not actively occurring (#10707)
  • Ensure hash history always includes a leading slash on hash pathnames (#10753)
  • Fixes an edge-case affecting web extensions in Firefox that use URLSearchParams and the useSearchParams hook (#10620)
  • Reorder effects in unstable_usePrompt to avoid throwing an exception if the prompt is unblocked and a navigation is performed synchronously (#10687, #10718)
  • SSR: Do not include hash in useFormAction() for unspecified actions since it cannot be determined on the server and causes hydration issues (#10758)
  • SSR: Fix an issue in queryRoute that was not always identifying thrown Response instances (#10717)
  • react-router-native: Update @ungap/url-search-params dependency from ^0.1.4 to ^0.2.2 (#10590)

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.15.0

v6.14.2

17 Jul 20:55
1acea8b
Compare
Choose a tag to compare

Patch Changes

  • Add missing <Form state> prop to populate history.state on submission navigations (#10630)
  • Trigger an error if a defer promise resolves/rejects with undefined in order to match the behavior of loaders and actions which must return a value or null (#10690)
  • Properly handle fetcher redirects interrupted by normal navigations (#10674)
  • Initial-load fetchers should not automatically revalidate on GET navigations (#10688)
  • Properly decode element id when emulating hash scrolling via <ScrollRestoration> (#10682)
  • Typescript: Enhance the return type of Route.lazy to prohibit returning an empty object (#10634)
  • SSR: Support proper hydration of Error subclasses such as ReferenceError/TypeError (#10633)

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.14.2

v6.14.1

30 Jun 19:16
8be5e51
Compare
Choose a tag to compare

Patch Changes

  • Fix loop in unstable_useBlocker when used with an unstable blocker function (#10652)
  • Fix issues with reused blockers on subsequent navigations (#10656)
  • Updated dependencies:

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.14.1

v6.14.0

23 Jun 20:00
09b6cbe
Compare
Choose a tag to compare

What's Changed

JSON/Text Submissions

6.14.0 adds support for JSON and Text submissions via useSubmit/fetcher.submit since it's not always convenient to have to serialize into FormData if you're working in a client-side SPA. To opt-into these encodings you just need to specify the proper formEncType:

Opt-into application/json encoding:

function Component() {
  let navigation = useNavigation();
  let submit = useSubmit();
  submit({ key: "value" }, { method: "post", encType: "application/json" });
  // navigation.formEncType => "application/json"
  // navigation.json        => { key: "value" }
}

async function action({ request }) {
  // request.headers.get("Content-Type") => "application/json"
  // await request.json()                => { key: "value" }
}

Opt-into text/plain encoding:

function Component() {
  let navigation = useNavigation();
  let submit = useSubmit();
  submit("Text submission", { method: "post", encType: "text/plain" });
  // navigation.formEncType => "text/plain"
  // navigation.text        => "Text submission"
}

async function action({ request }) {
  // request.headers.get("Content-Type") => "text/plain"
  // await request.text()                => "Text submission"
}

⚠️ Default Behavior Will Change in v7

Please note that to avoid a breaking change, the default behavior will still encode a simple key/value JSON object into a FormData instance:

function Component() {
  let navigation = useNavigation();
  let submit = useSubmit();
  submit({ key: "value" }, { method: "post" });
  // navigation.formEncType => "application/x-www-form-urlencoded"
  // navigation.formData    => FormData instance
}

async function action({ request }) {
  // request.headers.get("Content-Type") => "application/x-www-form-urlencoded"
  // await request.formData()            => FormData instance
}

This behavior will likely change in v7 so it's best to make any JSON object submissions explicit with formEncType: "application/x-www-form-urlencoded" or formEncType: "application/json" to ease your eventual v7 migration path.

Minor Changes

  • Add support for application/json and text/plain encodings for useSubmit/fetcher.submit. To reflect these additional types, useNavigation/useFetcher now also contain navigation.json/navigation.text and fetcher.json/fetcher.text which include the json/text submission if applicable. (#10413)

Patch Changes

  • When submitting a form from a submitter element, prefer the built-in new FormData(form, submitter) instead of the previous manual approach in modern browsers (those that support the new submitter parameter) (#9865)
    • For browsers that don't support it, we continue to just append the submit button's entry to the end, and we also add rudimentary support for type="image" buttons
    • If developers want full spec-compliant support for legacy browsers, they can use the formdata-submitter-polyfill
  • Call window.history.pushState/replaceState before updating React Router state (instead of after) so that window.location matches useLocation during synchronous React 17 rendering (#10448)
    • ⚠️ Note: generally apps should not be relying on window.location and should always reference useLocation when possible, as window.location will not be in sync 100% of the time (due to popstate events, concurrent mode, etc.)
  • Avoid calling shouldRevalidate for fetchers that have not yet completed a data load (#10623)
  • Strip basename from the location provided to <ScrollRestoration getKey> to match the useLocation behavior (#10550)
  • Strip basename from locations provided to unstable_useBlocker functions to match the useLocation behavior (#10573)
  • Fix unstable_useBlocker key issues in StrictMode (#10573)
  • Fix generatePath when passed a numeric 0 value parameter (#10612)
  • Fix tsc --skipLibCheck:false issues on React 17 (#10622)
  • Upgrade typescript to 5.1 (#10581)

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.14.0

v6.13.0

14 Jun 16:01
ed17fcd
Compare
Choose a tag to compare

What's Changed

6.13.0 is really a patch release in spirit but comes with a SemVer minor bump since we added a new future flag.

The tl;dr; is that 6.13.0 is the same as 6.12.0 bue we've moved the usage of React.startTransition behind an opt-in future.v7_startTransition future flag 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:

<BrowserRouter>
  <Routes>{/*...*/}</Routes>
</BrowserRouter>

<RouterProvider router={router} />

If you wish to enable React.startTransition, pass the future flag to your router component:

<BrowserRouter future={{ v7_startTransition: true }}>
  <Routes>{/*...*/}</Routes>
</BrowserRouter>

<RouterProvider router={router} future={{ v7_startTransition: true }}/>

We recommend folks adopt this flag sooner rather than later to be better compatible with React concurrent mode, but if you run into issues you can continue without the use of React.startTransition until v7. Issues usually boil down to creating net-new promises during the render cycle, so if you run into issues when opting into React.startTransition, you should either lift your promise creation out of the render cycle or put it behind a useMemo.

Minor Changes

  • Move React.startTransition usage behinds a future flag (#10596)

Patch Changes

  • Work around webpack/terser React.startTransition minification bug in production mode (#10588)

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.13.0

v6.12.1

08 Jun 16:49
77d7182
Compare
Choose a tag to compare

Warning
Please use version 6.13.0 or later instead of 6.12.0/6.12.1. These versions suffered from some Webpack build/minification issues resulting failed builds or invalid minified code in your production bundles. See #10569 and #10579 for more details.

Patch Changes

  • Adjust feature detection of React.startTransition to fix webpack + react 17 compilation error (#10569)

Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.12.1