-
Move
React.startTransitionusage behind a future flag to avoid issues with existing incompatibleSuspenseusages. We recommend folks adopting this flag to be better compatible with React concurrent mode, but if you run into issues you can continue without the use ofstartTransitionuntil v7. Issues usually boils down to creating net-new promises during the render cycle, so if you run into issues you should either lift your promise creation out of the render cycle or put it behind auseMemo. (#10596)Existing behavior will no longer include
React.startTransition:<BrowserRouter> <Routes>{/*...*/}</Routes> </BrowserRouter> <RouterProvider router={router} />
If you wish to enable
React.startTransition, pass the future flag to your component:<BrowserRouter future={{ v7_startTransition: true }}> <Routes>{/*...*/}</Routes> </BrowserRouter> <RouterProvider router={router} future={{ v7_startTransition: true }}/>
- Work around webpack/terser
React.startTransitionminification bug in production mode (#10588) - Updated dependencies:
react-router@6.13.0
Warning Please use version
6.13.0or later instead of6.12.1. This version suffers from awebpack/terserminification issue resulting in invalid minified code in your resulting production bundles which can cause issues in your application. See #10579 for more details.
- Adjust feature detection of
React.startTransitionto fix webpack + react 17 compilation error (#10569) - Updated dependencies:
react-router@6.12.1
- Wrap internal router state updates with
React.startTransitionif it exists (#10438)
- Re-throw
DOMException(DataCloneError) when attempting to perform aPUSHnavigation with non-serializable state. (#10427) - Updated dependencies:
@remix-run/router@1.6.3react-router@6.12.0
- Export
SetURLSearchParamstype (#10444) - Updated dependencies:
react-router@6.11.2@remix-run/router@1.6.2
- Updated dependencies:
react-router@6.11.1@remix-run/router@1.6.1
- Enable
basenamesupport inuseFetcher(#10336)- If you were previously working around this issue by manually prepending the
basenamethen you will need to remove the manually prependedbasenamefrom yourfetchercalls (fetcher.load('/basename/route') -> fetcher.load('/route'))
- If you were previously working around this issue by manually prepending the
- Fix inadvertent re-renders when using
Componentinstead ofelementon a route definition (#10287) - Fail gracefully on
<Link to="//">and other invalid URL values (#10367) - Switched from
useSyncExternalStoretouseStatefor internal@remix-run/routerrouter state syncing in<RouterProvider>. We found some subtle bugs where router state updates got propagated before other normaluseStateupdates, which could lead to footguns inuseEffectcalls. (#10377, #10409) - Add static prop to
StaticRouterProvider's internalRoutercomponent (#10401) - When using a
RouterProvider,useNavigate/useSubmit/fetcher.submitare now stable across location changes, since we can handle relative routing via the@remix-run/routerinstance and get rid of our dependence onuseLocation(). When usingBrowserRouter, these hooks remain unstable across location changes because they still rely onuseLocation(). (#10336) - Updated dependencies:
react-router@6.11.0@remix-run/router@1.6.0
-
Added support for Future Flags in React Router. The first flag being introduced is
future.v7_normalizeFormMethodwhich will normalize the exposeduseNavigation()/useFetcher()formMethodfields as uppercase HTTP methods to align with thefetch()behavior. (#10207)- When
future.v7_normalizeFormMethod === false(default v6 behavior),useNavigation().formMethodis lowercaseuseFetcher().formMethodis lowercase
- When
future.v7_normalizeFormMethod === true:useNavigation().formMethodis uppercaseuseFetcher().formMethodis uppercase
- When
- Fix
createStaticHandlerto also check forErrorBoundaryon routes in addition toerrorElement(#10190) - Updated dependencies:
@remix-run/router@1.5.0react-router@6.10.0
-
React Router now supports an alternative way to define your route
elementanderrorElementfields as React Components instead of React Elements. You can instead pass a React Component to the newComponentandErrorBoundaryfields 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/ErrorBoundarywill "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
loadingorsubmittingphase 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
lazyfunctions 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-providerdirectory of the repository.🙌 Huge thanks to @rossipedia for the Initial Proposal and POC Implementation.
-
Updated dependencies:
react-router@6.9.0@remix-run/router@1.4.0
- Treat same-origin absolute URLs in
<Link to>as external if they are outside of the routerbasename(#10135) - Fix
useBlockerto returnIDLE_BLOCKERduring SSR (#10046) - Fix SSR of absolute
<Link to>urls (#10112) - Properly escape HTML characters in
StaticRouterProviderserialized hydration data (#10068) - Updated dependencies:
@remix-run/router@1.3.3react-router@6.8.2
- Improved absolute url detection in
Linkcomponent (now also supportsmailto:urls) (#9994) - Fix partial object (search or hash only) pathnames losing current path value (#10029)
- Updated dependencies:
react-router@6.8.1@remix-run/router@1.3.2
-
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 */}
- Fix bug with search params removal via
useSearchParams(#9969) - Respect
preventScrollReseton<fetcher.Form>(#9963) - Fix navigation for hash routers on manual URL changes (#9980)
- Use
pagehideinstead ofbeforeunloadfor<ScrollRestoration>. This has better cross-browser support, specifically on Mobile Safari. (#9945) - Updated dependencies:
@remix-run/router@1.3.1react-router@6.8.0
- Add
unstable_useBlockerhook for blocking navigations within the app's location origin (#9709) - Add
unstable_usePrompthook for blocking navigations within the app's location origin (#9932) - Add
preventScrollResetprop to<Form>(#9886)
- Added pass-through event listener options argument to
useBeforeUnload(#9709) - Streamline jsdom bug workaround in tests (#9824)
- Updated dependencies:
@remix-run/router@1.3.0react-router@6.7.0
- Ensure
useIdconsistency during SSR (#9805) - Updated dependencies:
react-router@6.6.2
- Updated dependencies:
@remix-run/router@1.2.1react-router@6.6.1
- Add
useBeforeUnload()hook (#9664) - Remove
unstable_prefix fromcreateStaticHandler/createStaticRouter/StaticRouterProvider(#9738)
- Proper hydration of
Errorobjects fromStaticRouterProvider(#9664) - Support uppercase
<Form method>anduseSubmitmethod values (#9664) - Skip initial scroll restoration for SSR apps with
hydrationData(#9664) - Fix
<button formmethod>form submission overriddes (#9664) - Updated dependencies:
@remix-run/router@1.2.0react-router@6.6.0
- Updated dependencies:
react-router@6.5.0@remix-run/router@1.1.0
- Updated dependencies:
@remix-run/router@1.0.5react-router@6.4.5
- Fix issues with encoded characters in
NavLinkand descendant<Routes>(#9589, #9647) - Properly serialize/deserialize
ErrorResponseinstances when using built-in hydration (#9593) - Support
basenamein static data routers (#9591) - Updated dependencies:
@remix-run/router@1.0.4react-router@6.4.4
- Fix hrefs generated for
createHashRouter(#9409) - fix encoding/matching issues with special chars (#9477, #9496)
- Properly support
indexroutes with apathinuseResolvedPath(#9486) - Respect
relative=pathprop onNavLink(#9453) - Fix
NavLinkbehavior for root urls (#9497) - Updated dependencies:
@remix-run/router@1.0.3react-router@6.4.3
- Respect
basenameinuseFormAction(#9352) - Enhance console error messages for invalid usage of data router hooks (#9311)
- If an index route has children, it will result in a runtime error. We have strengthened our
RouteObject/RoutePropstypes to surface the error in TypeScript. (#9366) - Updated dependencies:
react-router@6.4.2@remix-run/router@1.0.2
- Updated dependencies:
react-router@6.4.1@remix-run/router@1.0.1
Whoa this is a big one! 6.4.0 brings all the data loading and mutation APIs over from Remix. Here's a quick high level overview, but it's recommended you go check out the docs, especially the feature overview and the tutorial.
New APIs
- Create your router with
createMemoryRouter/createBrowserRouter/createHashRouter - Render your router with
<RouterProvider> - Load data with a Route
loaderand mutate with a Routeaction - Handle errors with Route
errorElement - Submit data with the new
<Form>component - Perform in-page data loads and mutations with
useFetcher() - Defer non-critical data with
deferandAwait - Manage scroll position with
<ScrollRestoration>
New Features
- Perform path-relative navigations with
<Link relative="path">(#9160)
Bug Fixes
- Path resolution is now trailing slash agnostic (#8861)
useLocationreturns the scoped location inside a<Routes location>component (#9094)- respect the
<Link replace>prop if it is defined (#8779)
Updated Dependencies
react-router@6.4.0