Releases: remix-run/react-router
v6.11.0
What's Changed
Minor Changes
- Enable
basename
support inuseFetcher
(#10336)- If you were previously working around this issue by manually prepending the
basename
then you will need to remove the manually prependedbasename
from yourfetcher
calls (fetcher.load('/basename/route') -> fetcher.load('/route')
)
- If you were previously working around this issue by manually prepending the
- Updated dependencies:
@remix-run/[email protected]
(Changelog)
Patch Changes
- When using a
RouterProvider
,useNavigate
/useSubmit
/fetcher.submit
are now stable across location changes, since we can handle relative routing via the@remix-run/router
instance and get rid of our dependence onuseLocation()
(#10336)- When using
BrowserRouter
, these hooks remain unstable across location changes because they still rely onuseLocation()
- When using
- Fetchers should no longer revalidate on search params changes or routing to the same URL, and will only revalidate on
action
submissions orrouter.revalidate
calls (#10344) - Fix inadvertent re-renders when using
Component
instead ofelement
on a route definition (#10287) - Fail gracefully on
<Link to="//">
and other invalid URL values (#10367) - Switched from
useSyncExternalStore
touseState
for internal@remix-run/router
router state syncing in<RouterProvider>
. We found some subtle bugs where router state updates got propagated before other normaluseState
updates, which could lead to foot guns inuseEffect
calls. (#10377, #10409) - Log loader/action errors caught by the default error boundary to the console in dev for easier stack trace evaluation (#10286)
- Fix bug preventing rendering of descendant
<Routes>
whenRouterProvider
errors existed (#10374) - Fix detection of
useNavigate
in the render cycle by setting theactiveRef
in a layout effect, allowing thenavigate
function to be passed to child components and called in auseEffect
there (#10394) - Allow
useRevalidator()
to resolve a loader-driven error boundary scenario (#10369) - Enhance
LoaderFunction
/ActionFunction
return type to preventundefined
from being a valid return value (#10267) - Ensure proper 404 error on
fetcher.load
call to a route without aloader
(#10345) - Decouple
AbortController
usage between revalidating fetchers and the thing that triggered them such that the unmount/deletion of a revalidating fetcher doesn't impact the ongoing triggering navigation/revalidation (#10271)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.11.0
v6.10.0
What's Changed
We recently published a post over on the Remix Blog titled "Future Proofing Your Remix App" that goes through our strategy to ensure smooth upgrades for your Remix and React Router apps going forward. React Router 6.10.0
adds support for these flags (for data routers) which you can specify when you create your router:
const router = createBrowserRouter(routes, {
future: {
// specify future flags here
},
});
You can also check out the docs here and here.
Minor Changes
-
The first future flag being introduced is
future.v7_normalizeFormMethod
which will normalize the exposeduseNavigation()/useFetcher()
formMethod
fields as uppercase HTTP methods to align with thefetch()
(and some Remix) behavior. (#10207)- When
future.v7_normalizeFormMethod
is unspecified or set tofalse
(default v6 behavior),useNavigation().formMethod
is lowercaseuseFetcher().formMethod
is lowercase
- When
future.v7_normalizeFormMethod === true
:useNavigation().formMethod
is UPPERCASEuseFetcher().formMethod
is UPPERCASE
- When
Patch Changes
- Fix
createStaticHandler
to also check forErrorBoundary
on routes in addition toerrorElement
(#10190) - Fix route ID generation when using Fragments in
createRoutesFromElements
(#10193) - Provide fetcher submission to
shouldRevalidate
if the fetcher action redirects (#10208) - Properly handle
lazy()
errors during router initialization (#10201) - Remove
instanceof
check forDeferredData
to be resilient to ESM/CJS boundaries in SSR bundling scenarios (#10247) - Update to latest
@remix-run/[email protected]
(#10216)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.10.0
v6.9.0
What's Changed
Minor Changes
-
React Router now supports an alternative way to define your route
element
anderrorElement
fields as React Components instead of React Elements. You can instead pass a React Component to the newComponent
andErrorBoundary
fields if you choose. There is no functional difference between the two, so use whichever approach you prefer 😀. You shouldn't be defining both, but if you doComponent
/ErrorBoundary
will "win". (#10045)Example JSON Syntax
// Both of these work the same: const elementRoutes = [{ path: '/', element: <Home />, errorElement: <HomeError />, }] const componentRoutes = [{ path: '/', Component: Home, ErrorBoundary: HomeError, }] function Home() { ... } function HomeError() { ... }
Example JSX Syntax
// Both of these work the same: const elementRoutes = createRoutesFromElements( <Route path='/' element={<Home />} errorElement={<HomeError /> } /> ); const componentRoutes = createRoutesFromElements( <Route path='/' Component={Home} ErrorBoundary={HomeError} /> ); function Home() { ... } function HomeError() { ... }
-
Introducing Lazy Route Modules! (#10045)
In order to keep your application bundles small and support code-splitting of your routes, we've introduced a new
lazy()
route property. This is an async function that resolves the non-route-matching portions of your route definition (loader
,action
,element
/Component
,errorElement
/ErrorBoundary
,shouldRevalidate
,handle
).Lazy routes are resolved on initial load and during the
loading
orsubmitting
phase of a navigation or fetcher call. You cannot lazily define route-matching properties (path
,index
,children
) since we only execute your lazy route functions after we've matched known routes.Your
lazy
functions will typically return the result of a dynamic import.// In this example, we assume most folks land on the homepage so we include that // in our critical-path bundle, but then we lazily load modules for /a and /b so // they don't load until the user navigates to those routes let routes = createRoutesFromElements( <Route path="/" element={<Layout />}> <Route index element={<Home />} /> <Route path="a" lazy={() => import("./a")} /> <Route path="b" lazy={() => import("./b")} /> </Route> );
Then in your lazy route modules, export the properties you want defined for the route:
export async function loader({ request }) { let data = await fetchData(request); return json(data); } // Export a `Component` directly instead of needing to create a React Element from it export function Component() { let data = useLoaderData(); return ( <> <h1>You made it!</h1> <p>{data}</p> </> ); } // Export an `ErrorBoundary` directly instead of needing to create a React Element from it export function ErrorBoundary() { let error = useRouteError(); return isRouteErrorResponse(error) ? ( <h1> {error.status} {error.statusText} </h1> ) : ( <h1>{error.message || error}</h1> ); }
An example of this in action can be found in the
examples/lazy-loading-router-provider
directory of the repository. For more info, check out thelazy
docs.🙌 Huge thanks to @rossipedia for the Initial Proposal and POC Implementation.
Patch Changes
- Improve memoization for context providers to avoid unnecessary re-renders (#9983)
- Fix
generatePath
incorrectly applying parameters in some cases (#10078) [react-router-dom-v5-compat]
Add missed data router API re-exports (#10171)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.9.0
v6.8.2
What's Changed
- Treat same-origin absolute URLs in
<Link to>
as external if they are outside of the routerbasename
(#10135) - Correctly perform a hard redirect for same-origin absolute URLs outside of the router
basename
(#10076) - Fix SSR of absolute
<Link to>
urls (#10112) - Properly escape HTML characters in
StaticRouterProvider
serialized hydration data (#10068) - Fix
useBlocker
to returnIDLE_BLOCKER
during SSR (#10046) - Ensure status code and headers are maintained for
defer
loader responses increateStaticHandler
'squery()
method (#10077) - Change
invariant
to anUNSAFE_invariant
export since it's only intended for internal use (#10066)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.8.2
v6.8.1
What's Changed
- Remove inaccurate console warning for POP navigations and update active blocker logic (#10030)
- Only check for differing origin on absolute URL redirects (#10033)
- Improved absolute url detection in
Link
component (now also supportsmailto:
urls) (#9994) - Fix partial object (search or hash only) pathnames losing current path value (#10029)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.8.1
v6.8.0
What's Changed
Minor Changes
Support absolute URLs in <Link to>
. If the URL is for the current origin, it will still do a client-side navigation. If the URL is for a different origin then it will do a fresh document request for the new origin. (#9900)
<Link to="https://neworigin.com/some/path"> {/* Document request */}
<Link to="//neworigin.com/some/path"> {/* Document request */}
<Link to="https://www.currentorigin.com/path"> {/* Client-side navigation */}
Patch Changes
- Fixes 2 separate issues for revalidating fetcher
shouldRevalidate
calls (#9948)- The
shouldRevalidate
function was only being called for explicit revalidation scenarios (after a mutation, manualuseRevalidator
call, or anX-Remix-Revalidate
header used for cookie setting in Remix). It was not properly being called on implicit revalidation scenarios that also apply to navigationloader
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 staticfetcher.load
URL (and thus were identical). Instead, they should have reflected the the navigation that triggered the revalidation (as theform*
parameters did). These parameters now correctly reflect the triggering navigation.
- The
- Fix bug with search params removal via
useSearchParams
(#9969) - Respect
preventScrollReset
on<fetcher.Form>
(#9963) - Fix navigation for hash routers on manual URL changes (#9980)
- Use
pagehide
instead ofbeforeunload
for<ScrollRestoration>
. This has better cross-browser support, specifically on Mobile Safari. (#9945) - Do not short circuit on hash change only mutation submissions (#9944)
- Remove
instanceof
check fromisRouteErrorResponse
to avoid bundling issues on the server (#9930) - Detect when a
defer
call only contains critical data and remove theAbortController
(#9965) - Send the name as the value when url-encoding
File
FormData
entries (#9867) react-router-dom-v5-compat
- Fix SSRuseLayoutEffect
console.error
when usingCompatRouter
(#9820)
New Contributors
- @fyzhu made their first contribution in #9874
- @cassidoo made their first contribution in #9889
- @machour made their first contribution in #9893
- @jdufresne made their first contribution in #9916
- @LordThi made their first contribution in #9953
- @bbrowning918 made their first contribution in #9954
Full Changelog: v6.7.0...v6.8.0
v6.7.0
What's Changed
Minor Changes
- Add
unstable_useBlocker
/unstable_usePrompt
hooks for blocking navigations within the app's location origin (#9709, #9932) - Add
preventScrollReset
prop to<Form>
(#9886)
Patch Changes
- Added pass-through event listener options argument to
useBeforeUnload
(#9709) - Fix
generatePath
when optional params are present (#9764) - Update
<Await>
to acceptReactNode
as children function return result (#9896) - Improved absolute redirect url detection in actions/loaders (#9829)
- Fix URL creation with memory histories (#9814)
- Fix scroll reset if a submission redirects (#9886)
- Fix 404 bug with same-origin absolute redirects (#9913)
- Streamline
jsdom
bug workaround in tests (#9824)
New Contributors
- @damianstasik made their first contribution in #9835
- @akamfoad made their first contribution in #9877
- @lkwr made their first contribution in #9829
Full Changelog: v6.6.2...v6.7.0
v6.6.2
What's Changed
- Ensure
useId
consistency during SSR (#9805)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.6.2
v6.6.1
What's Changed
- Include submission info in
shouldRevalidate
on action redirects (#9777, #9782) - Reset
actionData
on action redirect to current location (#9772)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.6.1
v6.6.0
What's Changed
This minor release is primarily to stabilize our SSR APIs for Data Routers now that we've wired up the new RouterProvider
in Remix as part of the React Router-ing Remix work.
Minor Changes
- Remove
unstable_
prefix fromcreateStaticHandler
/createStaticRouter
/StaticRouterProvider
(#9738) - Add
useBeforeUnload()
hook (#9664)
Patch Changes
- Support uppercase
<Form method>
anduseSubmit
method values (#9664) - Fix
<button formmethod>
form submission overriddes (#9664) - Fix explicit
replace
on submissions andPUSH
on submission to new paths (#9734) - Prevent
useLoaderData
usage inerrorElement
(#9735) - Proper hydration of
Error
objects fromStaticRouterProvider
(#9664) - Skip initial scroll restoration for SSR apps with
hydrationData
(#9664) - Fix a few bugs where loader/action data wasn't properly cleared on errors (#9735)
Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.6.0