25 KiB
@remix-run/router
1.9.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
- 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)
1.8.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
- Fix an issue in
queryRoute
that was not always identifying thrownResponse
instances (#10717) - Ensure hash history always includes a leading slash on hash pathnames (#10753)
1.7.2
Patch Changes
- 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, #10709)
- Initial-load fetchers should not automatically revalidate on GET navigations (#10688)
- Enhance the return type of
Route.lazy
to prohibit returning an empty object (#10634)
1.7.1
Patch Changes
- Fix issues with reused blockers on subsequent navigations (#10656)
1.7.0
Minor Changes
-
Add support for
application/json
andtext/plain
encodings forrouter.navigate
/router.fetch
submissions. To leverage these encodings, pass your data in abody
parameter and specify the desiredformEncType
: (#10413)// By default, the encoding is "application/x-www-form-urlencoded" router.navigate("/", { formMethod: "post", body: { key: "value" }, }); async function action({ request }) { // await request.formData() => FormData instance with entry [key=value] }
// Pass `formEncType` to opt-into a different encoding (json) router.navigate("/", { formMethod: "post", formEncType: "application/json", body: { key: "value" }, }); async function action({ request }) { // await request.json() => { key: "value" } }
// Pass `formEncType` to opt-into a different encoding (text) router.navigate("/", { formMethod: "post", formEncType: "text/plain", body: "Text submission", }); async function action({ request }) { // await request.text() => "Text submission" }
Patch Changes
- Call
window.history.pushState/replaceState
before updating React Router state (instead of after) so thatwindow.location
matchesuseLocation
during synchronous React 17 rendering (#10448)- ⚠️ However, generally apps should not be relying on
window.location
and should always referenceuseLocation
when possible, aswindow.location
will not be in sync 100% of the time (due topopstate
events, concurrent mode, etc.)
- ⚠️ However, generally apps should not be relying on
- Strip
basename
from thelocation
provided to<ScrollRestoration getKey>
to match theuseLocation
behavior (#10550) - Avoid calling
shouldRevalidate
for fetchers that have not yet completed a data load (#10623) - Fix
unstable_useBlocker
key issues inStrictMode
(#10573) - Upgrade
typescript
to 5.1 (#10581)
1.6.3
Patch Changes
- Allow fetcher revalidations to complete if submitting fetcher is deleted (#10535)
- Re-throw
DOMException
(DataCloneError
) when attempting to perform aPUSH
navigation with non-serializable state. (#10427) - Ensure revalidations happen when hash is present (#10516)
- upgrade jest and jsdom (#10453)
1.6.2
Patch Changes
- Fix HMR-driven error boundaries by properly reconstructing new routes and
manifest
in\_internalSetRoutes
(#10437) - Fix bug where initial data load would not kick off when hash is present (#10493)
1.6.1
Patch Changes
- Fix
basename
handling when navigating without a path (#10433) - "Same hash" navigations no longer re-run loaders to match browser behavior (i.e.
/path#hash -> /path#hash
) (#10408)
1.6.0
Minor Changes
-
Enable relative routing in the
@remix-run/router
when providing a source route ID from which the path is relative to: (#10336)- Example:
router.navigate("../path", { fromRouteId: "some-route" })
. - This also applies to
router.fetch
which already receives a source route ID
- Example:
-
Introduce a new
@remix-run/router
future.v7_prependBasename
flag to enablebasename
prefixing to all paths coming intorouter.navigate
androuter.fetch
.- Previously the
basename
was prepended in the React Router layer, but now that relative routing is being handled by the router we need prepend thebasename
after resolving any relative paths - This also enables
basename
support inuseFetcher
as well
- Previously the
Patch Changes
- 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) - Deprecate the
createRouter
detectErrorBoundary
option in favor of the newmapRouteProperties
option for converting a framework-agnostic route to a framework-aware route. This allows us to set more than just thehasErrorBoundary
property during route pre-processing, and is now used for mappingComponent -> element
andErrorBoundary -> errorElement
inreact-router
. (#10287) - Fixed a bug where fetchers were incorrectly attempting to revalidate on search params changes or routing to the same URL (using the same logic for route
loader
revalidations). However, since fetchers have a static href, they should only revalidate onaction
submissions orrouter.revalidate
calls. (#10344) - 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)
1.5.0
Minor Changes
-
Added support for Future Flags in React Router. The first flag being introduced is
future.v7_normalizeFormMethod
which will normalize the exposeduseNavigation()/useFetcher()
formMethod
fields as uppercase HTTP methods to align with thefetch()
behavior. (#10207)- When
future.v7_normalizeFormMethod === false
(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
- 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/web-fetch@4.3.3
(#10216)
1.4.0
Minor Changes
-
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.🙌 Huge thanks to @rossipedia for the Initial Proposal and POC Implementation.
Patch Changes
- Fix
generatePath
incorrectly applying parameters in some cases (#10078)
1.3.3
Patch Changes
- Correctly perform a hard redirect for same-origin absolute URLs outside of the router
basename
(#10076) - 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) - Add internal API for custom HMR implementations (#9996)
1.3.2
Patch Changes
- Remove inaccurate console warning for POP navigations and update active blocker logic (#10030)
- Only check for differing origin on absolute URL redirects (#10033)
1.3.1
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
- Respect
preventScrollReset
on<fetcher.Form>
(#9963) - Do not short circuit on hash change only mutation submissions (#9944)
- Remove
instanceof
check fromisRouteErrorResponse
to avoid bundling issues on the server (#9930) - Fix navigation for hash routers on manual URL changes (#9980)
- 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)
1.3.0
Minor Changes
- Added support for navigation blocking APIs (#9709)
- Expose deferred information from
createStaticHandler
(#9760)
Patch Changes
- Improved absolute redirect url detection in actions/loaders (#9829)
- Fix URL creation with memory histories (#9814)
- Fix
generatePath
when optional params are present (#9764) - Fix scroll reset if a submission redirects (#9886)
- Fix 404 bug with same-origin absolute redirects (#9913)
- Support
OPTIONS
requests instaticHandler.queryRoute
(#9914)
1.2.1
Patch Changes
- Include submission info in
shouldRevalidate
on action redirects (#9777, #9782) - Reset
actionData
on action redirect to current location (#9772)
1.2.0
Minor Changes
- Remove
unstable_
prefix fromcreateStaticHandler
/createStaticRouter
/StaticRouterProvider
(#9738)
Patch Changes
- Fix explicit
replace
on submissions andPUSH
on submission to new paths (#9734) - Fix a few bugs where loader/action data wasn't properly cleared on errors (#9735)
- Prevent
useLoaderData
usage inerrorElement
(#9735) - Skip initial scroll restoration for SSR apps with
hydrationData
(#9664)
1.1.0
This release introduces support for Optional Route Segments. Now, adding a ?
to the end of any path segment will make that entire segment optional. This works for both static segments and dynamic parameters.
Optional Params Examples
- Path
lang?/about
will match:/:lang/about
/about
- Path
/multistep/:widget1?/widget2?/widget3?
will match:/multistep
/multistep/:widget1
/multistep/:widget1/:widget2
/multistep/:widget1/:widget2/:widget3
Optional Static Segment Example
- Path
/home?
will match:/
/home
- Path
/fr?/about
will match:/about
/fr/about
Minor Changes
- Allows optional routes and optional static segments (#9650)
Patch Changes
- Stop incorrectly matching on partial named parameters, i.e.
<Route path="prefix-:param">
, to align with how splat parameters work. If you were previously relying on this behavior then it's recommended to extract the static portion of the path at theuseParams
call site: (#9506)
// Old behavior at URL /prefix-123
<Route path="prefix-:id" element={<Comp /> }>
function Comp() {
let params = useParams(); // { id: '123' }
let id = params.id; // "123"
...
}
// New behavior at URL /prefix-123
<Route path=":id" element={<Comp /> }>
function Comp() {
let params = useParams(); // { id: 'prefix-123' }
let id = params.id.replace(/^prefix-/, ''); // "123"
...
}
- Persist
headers
onloader
request
's after SSR documentaction
request (#9721) - Fix requests sent to revalidating loaders so they reflect a GET request (#9660)
- Fix issue with deeply nested optional segments (#9727)
- GET forms now expose a submission on the loading navigation (#9695)
- Fix error boundary tracking for multiple errors bubbling to the same boundary (#9702)
1.0.5
Patch Changes
- Fix requests sent to revalidating loaders so they reflect a
GET
request (#9680) - Remove
instanceof Response
checks in favor ofisResponse
(#9690) - Fix
URL
creation in Cloudflare Pages or other non-browser-environments (#9682, #9689) - Add
requestContext
support to static handlerquery
/queryRoute
(#9696)- Note that the unstable API of
queryRoute(path, routeId)
has been changed toqueryRoute(path, { routeId, requestContext })
- Note that the unstable API of
1.0.4
Patch Changes
- Throw an error if an
action
/loader
function returnsundefined
as revalidations need to know whether the loader has previously been executed.undefined
also causes issues during SSR stringification for hydration. You should always ensure youloader
/action
returns a value, and you may returnnull
if you don't wish to return anything. (#9511) - Properly handle redirects to external domains (#9590, #9654)
- Preserve the HTTP method on 307/308 redirects (#9597)
- Support
basename
in static data routers (#9591) - Enhanced
ErrorResponse
bodies to contain more descriptive text in internal 403/404/405 scenarios
1.0.3
Patch Changes
- Fix hrefs generated when using
createHashRouter
(#9409) - fix encoding/matching issues with special chars (#9477, #9496)
- Support
basename
and relative routing inloader
/action
redirects (#9447) - Ignore pathless layout routes when looking for proper submission
action
function (#9455) - properly support
index
routes with apath
inuseResolvedPath
(#9486) - Add UMD build for
@remix-run/router
(#9446) - fix
createURL
in local file execution in Firefox (#9464) - Updates to
unstable_createStaticHandler
for incorporating into Remix (#9482, #9465)
1.0.2
Patch Changes
- Reset
actionData
after a successful action redirect (#9334) - Update
matchPath
to avoid false positives on dash-separated segments (#9300) - If an index route has children, it will result in a runtime error. We have strengthened our
RouteObject
/RouteProps
types to surface the error in TypeScript. (#9366)
1.0.1
Patch Changes
- Preserve state from
initialEntries
(#9288) - Preserve
?index
for fetcher get submissions to index routes (#9312)
1.0.0
This is the first stable release of @remix-run/router
, which provides all the underlying routing and data loading/mutation logic for react-router
. You should not be using this package directly unless you are authoring a routing library similar to react-router
.
For an overview of the features provided by react-router
, we recommend you go check out the docs, especially the feature overview and the tutorial.
For an overview of the features provided by @remix-run/router
, please check out the README
.