Releases: remix-run/react-router
v6.21.0
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6210
v6.20.1
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6201
v6.20.0
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6200
v6.19.0
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6190
v6.18.0
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 bykey
Form
anduseSumbit
now support optionalnavigate
/fetcherKey
props/params to allow kicking off a fetcher submission under the hood with an optionally user-specifiedkey
<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()
oruseFetcher({ 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 anidle
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 viauseFetcher().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
- They will remain exposed via
- Fetchers that complete while still mounted will no longer appear in
Other Minor Changes
- Add support for optional path segments in
matchPath
(#10768)
Patch Changes
- Fix the
future
prop onBrowserRouter
,HashRouter
andMemoryRouter
so that it accepts aPartial<FutureConfig>
instead of requiring all flags to be included (#10962) - Fix
router.getFetcher
/router.deleteFetcher
type definitions which incorrectly specifiedkey
as an optional parameter (#10960)
Full Changelog: 6.17.0...6.18.0
v6.17.0
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
whensessionStorage
is unavailable (#10848) - Fix
RouterProvider
future
prop type to be aPartial<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
Minor Changes
- In order to move towards stricter TypeScript support in the future, we're aiming to replace current usages of
any
withunknown
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 toany
in React Router and are overridden withunknown
in Remix. In React Router v7 we plan to move these tounknown
as a breaking change. (#10843)Location
now accepts a generic for thelocation.state
valueActionFunctionArgs
/ActionFunction
/LoaderFunctionArgs
/LoaderFunction
now accept a generic for thecontext
parameter (only used in SSR usages viacreateStaticHandler
)- The return type of
useMatches
(now exported asUIMatch
) accepts generics formatch.data
andmatch.handle
- both of which were already set tounknown
- Move the
@private
class exportErrorResponse
to anUNSAFE_ErrorResponseImpl
export since it is an implementation detail and there should be no construction ofErrorResponse
instances in userland. This frees us up to export atype ErrorResponse
which correlates to an instance of the class viaInstanceType
. Userland code should only ever be usingErrorResponse
as a type and should be type-narrowing viaisRouteErrorResponse
. (#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 toshouldRevalidate
(#10779)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.16.0
v6.15.0
Minor Changes
- Add's a new
redirectDocument()
function which allows users to specify that a redirect from aloader
/action
should trigger a document reload (viawindow.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 theuseSearchParams
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 thrownResponse
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
Patch Changes
- Add missing
<Form state>
prop to populatehistory.state
on submission navigations (#10630) - Trigger an error if a
defer
promise resolves/rejects withundefined
in order to match the behavior of loaders and actions which must return a value ornull
(#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 asReferenceError
/TypeError
(#10633)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.14.2
v6.14.1
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:
@remix-run/[email protected]
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.14.1