-
Add support for
clientLoader
/clientAction
/HydrateFallback
route exports (RFC). (#8173)Remix now supports loaders/actions that run on the client (in addition to, or instead of the loader/action that runs on the server). While we still recommend server loaders/actions for the majority of your data needs in a Remix app - these provide some levers you can pull for more advanced use-cases such as:
- Leveraging a data source local to the browser (i.e.,
localStorage
) - Managing a client-side cache of server data (like
IndexedDB
) - Bypassing the Remix server in a BFF setup and hitting your API directly from the browser
- Migrating a React Router SPA to a Remix application
By default,
clientLoader
will not run on hydration, and will only run on subsequent client side navigations.If you wish to run your client loader on hydration, you can set
clientLoader.hydrate=true
to force Remix to execute it on initial page load. Keep in mind that Remix will still SSR your route component so you should ensure that there is no new required data being added by yourclientLoader
.If your
clientLoader
needs to run on hydration and adds data you require to render the route component, you can export aHydrateFallback
component that will render during SSR, and then your route component will not render until theclientLoader
has executed on hydration.clientAction
is simpler thanclientLoader
because it has no hydration use-cases.clientAction
will only run on client-side navigations.For more information, please refer to the
clientLoader
andclientAction
documentation. - Leveraging a data source local to the browser (i.e.,
-
Add a new
future.v3_relativeSplatPath
flag to implement a breaking bug fix to relative routing when inside a splat route. For more information, please see the React Router6.21.0
Release Notes and theuseResolvedPath
docs. (#8216)
- Updated dependencies:
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
- Remove the
unstable_
prefix from theuseBlocker
hook as it's been in use for enough time that we are confident in the API. We do not plan to remove the prefix fromunstable_usePrompt
due to differences in how browsers handlewindow.confirm
that prevent React Router from guaranteeing consistent/correct behavior. (#7882)
- Support rendering of
LiveReload
component afterScripts
in Vite dev (#7919) - Support optional rendering of
LiveReload
component in Vite dev (#7919) - add missing modulepreload for the manifest (#7684)
- Updated dependencies:
- Unstable Vite support for Node-based Remix apps (#7590)
remix build
👉vite build && vite build --ssr
remix dev
👉vite dev
- Other runtimes (e.g. Deno, Cloudflare) not yet supported.
- See "Future > Vite" in the Remix Docs for details
- Add a new
future.v3_fetcherPersist
flag to change the persistence behavior of fetchers. Instead of being immediately cleaned up when unmounted in the UI, fetchers will persist until they return to anidle
state (RFC) (#7704)- For more details, please refer to the React Router 6.18.0 release notes
- Fix warning that could be logged when using route files with no
default
export (#7745)- It seems our compiler compiles these files to export an empty object as the
default
which we can then end up passing toReact.createElement
, triggering the console warning, but generally no UI issues - By properly detecting these, we can correctly pass
Component: undefined
off to the React Router layer - This is technically an potential issue in the compiler but it's an easy patch in the
@remix-run/react
layer and hopefully disappears in a Vite world
- It seems our compiler compiles these files to export an empty object as the
- Fix critical CSS hydration errors for Vite dev (#7812)
- Updated dependencies:
- Add experimental support for the View Transitions API via
document.startViewTransition
to enable CSS animated transitions on SPA navigations in your application (#7648)- For additional information please refer to the 2.1.0 Release Notes or the documentation
- Avoid mutating
meta
object whentagName
is specified (#7594) - Fix FOUC on subsequent client-side navigations to
route.lazy
routes (#7576) - Emulate types for
JSON.parse(JSON.stringify(x))
inSerializeFrom
(#7605)- Notably, type fields that are only assignable to
undefined
after serialization are now omitted sinceJSON.stringify |> JSON.parse
will omit them -- see test cases for examples - Also fixes type errors when upgrading to v2 from 1.19
- Notably, type fields that are only assignable to
- Export the proper Remix
useMatches
wrapper to fixUIMatch
typings (#7551) - Updated dependencies:
- Add second generic to
UIMatch
forhandle
field (#7464) - Fix resource routes being loaded through
route.lazy
(#7498) - Throw a semantically correct 405
ErrorResponse
instead of just anError
when submitting to a route without anaction
(#7423) - Updated dependencies:
@remix-run/[email protected]
-
Drop React 17 support (#7121)
-
Require Node >=18.0.0 (#6939)
-
Remove
unstable_shouldReload
, which has been replaced byshouldRevalidate
(#6865) -
The route
meta
API now defaults to the new "V2 Meta" API (#6958)- Please refer to the (docs and Preparing for V2 guide for more information.
-
Promote the
future.v2_dev
flag inremix.config.js
to a root leveldev
config (#7002) -
Remove
v2_errorBoundary
flag andCatchBoundary
implementation (#6906) -
Remove back-compat layer for
useFetcher
/useFetchers
, which includes a few small breaking changes (#6874)fetcher.type
has been removed since it can be derived from other available information- "Submission" fields have been flattened from
fetcher.submission
down onto the rootfetcher
object, and prefixed withform
in some cases (fetcher.submission.action
=>fetcher.formAction
) <fetcher.Form method="get">
is now more accurately categorized asstate:"loading"
instead ofstate:"submitting"
to better align with the underlying GET request
-
Remove
v2_normalizeFormMethod
future flag - allformMethod
values will be normalized in v2 (#6875) -
Remove deprecated
useTransition
hook in favor ofuseNavigation
-useNavigation
is almost identical with a few exceptions: (#6870)useTransition.type
has been removed since it can be derived from other available information- "Submission" fields have been flattened from
useTransition().submission
down onto the rootuseNavigation()
object <Form method="get">
is now more accurately categorized asstate:"loading"
instead ofstate:"submitting"
to better align with the underlying GET navigation
-
Remove
v2_routeConvention
flag - the flat route file convention is now standard. (#6969) -
Remove
v2_headers
flag - it is now the default behavior to use the deepestheaders
function in the route tree. (#6979) -
Removed/adjusted types to prefer
unknown
overany
and to align with underlying React Router types (#7319, #7354):- Renamed the
useMatches()
return type fromRouteMatch
toUIMatch
- Renamed
LoaderArgs
/ActionArgs
toLoaderFunctionArgs
/ActionFunctionArgs
AppData
changed fromany
tounknown
Location["state"]
(useLocation.state
) changed fromany
tounknown
UIMatch["data"]
(useMatches()[i].data
) changed fromany
tounknown
UIMatch["handle"]
(useMatches()[i].handle
) changed from{ [k: string]: any }
tounknown
Fetcher["data"]
(useFetcher().data
) changed fromany
tounknown
MetaMatch.handle
(used inmeta()
) changed fromany
tounknown
AppData
/RouteHandle
are no longer exported as they are just aliases forunknown
- Renamed the
-
Remove
imagesizes
&imagesrcset
properties fromHtmlLinkDescriptor
,LinkDescriptor
&PrefetchPageDescriptor
types (#6936) -
Remove deprecated
REMIX_DEV_SERVER_WS_PORT
env var (#6965)- use
remix dev
's '--port
/port
option instead
- use
-
Removed support for "magic exports" from the
remix
package. This package can be removed from yourpackage.json
and you should update all imports to use the source@remix-run/*
packages: (#6895)- import type { ActionArgs } from "remix"; - import { json, useLoaderData } from "remix"; + import type { ActionArgs } from "@remix-run/node"; + import { json } from "@remix-run/node"; + import { useLoaderData } from "@remix-run/react";
- Export the
Navigation
type returned fromuseNavigation
(#7136) - Update Remix to use React Router
route.lazy
for module loading (#7133)
-
Add
error
tometa()
params so you can render error titles, etc. (#7105)export function meta({ error }) { return [{ title: error.message }]; }
-
Re-Export
ShouldRevalidateFunctionArgs
type from React Router (#7316) -
Deduplicate prefetch
link
tags (#7060) -
Skip preloading of stylesheets on client-side route transitions if the browser does not support
<link rel=preload>
(#7106)- This prevents us from hanging on client-side navigations when we try to preload stylesheets and never receive a
load
/error
event on thelink
tag
- This prevents us from hanging on client-side navigations when we try to preload stylesheets and never receive a
-
Export proper
ErrorResponse
type for usage alongsideisRouteErrorResponse
(#7244) -
Use the hostname from
REMIX_DEV_ORIGIN
to connect to the live reload socket (#6923) -
Use unique key for
script:ld+json
meta descriptors (#6954) -
Fix live reload port when set explicitly as a prop (#7358)
-
Fix types for
useLoaderData
when using Yarn PnP (#7137) -
Updated dependencies:
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.19.3.
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.19.2.
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.19.1.
-
improved networking options for
v2_dev
(#6724)deprecate the
--scheme
and--host
options and replace them with theREMIX_DEV_ORIGIN
environment variable -
Added some missing react-router exports to
@remix-run/react
(#6856)
- Narrowed the type of
fetcher.formEncType
to useFormEncType
fromreact-router-dom
instead ofstring
(#6810) - Deferred promises that return undefined/void now surface a serialization error. (#6793)
- Properly handle
?_data
HTTP/Network errors that don't reach the Remix server and ensure they bubble to theErrorBoundary
(#6783) - Support proper hydration of
Error
subclasses such asReferenceError
/TypeError
in development mode (#6675) - fix router race condition for hmr (#6767)
- Avoid re-prefetching stylesheets for active routes during a revalidation (#6679)
- Add generic type for
useRouteLoaderData()
(#5157) - Bump RR 6.14.2 (#6854)
- Updated dependencies:
- Fix reload loops in scenarios where CDNs ignore search params (#6707)
- Updated dependencies:
- stabilize v2 dev server (#6615)
- Support
application/json
andtext/plain
submission encodings inuseSubmit
/fetcher.submit
(#6570) - Add support for
<Link prefetch="viewport">
to prefetch links when they enter the viewport via an Intersection Observer (#6433)
- Bump router 6.14.0-pre.1 (#6662)
- Detect mismatches between the initially loaded URL and the URL at the time we hydrate and trigger a hard reload if they do not match. This is an edge-case that can happen when the network is slowish and the user clicks forward into a Remix app and then clicks forward again while the initial JS chunks are loading. (#6409)
- Lock in react router 6.14.0 (#6677)
- properly pass props to inline script tags for deferred data (#6389)
- Updated dependencies:
-
Faster server export removal for routes when
unstable_dev
is enabled. (#6455)Also, only render modulepreloads on SSR. Do not render modulepreloads when hydrated.
-
Force Typescript to simplify type produced by
Serialize
. (#6449)As a result, the following types and functions have simplified return types:
- SerializeFrom
- useLoaderData
- useActionData
- useFetcher
type Data = { hello: string; when: Date }; // BEFORE type Unsimplified = SerializeFrom<Data>; // ^? SerializeObject<UndefinedToOptional<{ hello: string; when: Date }>> // AFTER type Simplified = SerializeFrom<Data>; // ^? { hello: string; when: string }
-
Reuse dev server port for WebSocket (Live Reload,HMR,HDR) (#6476)
As a result the
webSocketPort
/--websocket-port
option has been obsoleted. Additionally, scheme/host/port options for the dev server have been renamed.Available options are:
Option flag config default Command -c
/--command
command
remix-serve <server build path>
Scheme --scheme
scheme
http
Host --host
host
localhost
Port --port
port
Dynamically chosen open port No restart --no-restart
restart: false
restart: true
Note that scheme/host/port options are for the dev server, not your app server. You probably don't need to use scheme/host/port option if you aren't configuring networking (e.g. for Docker or SSL).
- retry HDR revalidations in development mode to aid in 3rd party server race conditions (#6287)
- Updated dependencies:
- Cross-module
loader
change detection for HDR (#6299) - Better opt-out of
loader
revalidation on UI only changes (#6278) - Add
useMatch
re-export fromreact-router-dom
(#5257) - Fix
data
parameter typing onV2_MetaFunction
to includeundefined
for scenarios in which theloader
threw to it's own boundary. (#6231) - Updated dependencies:
-
Enable support for CSS Modules, Vanilla Extract and CSS side-effect imports (#6046)
These CSS bundling features were previously only available via
future.unstable_cssModules
,future.unstable_vanillaExtract
andfuture.unstable_cssSideEffectImports
options inremix.config.js
, but they have now been stabilized.In order to use these features, check out our guide to CSS bundling in your project.
-
Stabilize built-in PostCSS support via the new
postcss
option inremix.config.js
. As a result, thefuture.unstable_postcss
option has also been deprecated. (#5960)The
postcss
option isfalse
by default, but when set totrue
will enable processing of all CSS files using PostCSS ifpostcss.config.js
is present.If you followed the original PostCSS setup guide for Remix, you may have a folder structure that looks like this, separating your source files from its processed output:
. ├── app │ └── styles (processed files) │ ├── app.css │ └── routes │ └── index.css └── styles (source files) ├── app.css └── routes └── index.css
After you've enabled the new
postcss
option, you can delete the processed files fromapp/styles
folder and move your source files fromstyles
toapp/styles
:. ├── app │ └── styles (source files) │ ├── app.css │ └── routes │ └── index.css
You should then remove
app/styles
from your.gitignore
file since it now contains source files rather than processed output.You can then update your
package.json
scripts to remove any usage ofpostcss
since Remix handles this automatically. For example, if you had followed the original setup guide:{ "scripts": { - "dev:css": "postcss styles --base styles --dir app/styles -w", - "build:css": "postcss styles --base styles --dir app/styles --env production", - "dev": "concurrently \"npm run dev:css\" \"remix dev\"" + "dev": "remix dev" } }
-
Stabilize built-in Tailwind support via the new
tailwind
option inremix.config.js
. As a result, thefuture.unstable_tailwind
option has also been deprecated. (#5960)The
tailwind
option isfalse
by default, but when set totrue
will enable built-in support for Tailwind functions and directives in your CSS files iftailwindcss
is installed.If you followed the original Tailwind setup guide for Remix and want to make use of this feature, you should first delete the generated
app/tailwind.css
.Then, if you have a
styles/tailwind.css
file, you should move it toapp/tailwind.css
.rm app/tailwind.css mv styles/tailwind.css app/tailwind.css
Otherwise, if you don't already have an
app/tailwind.css
file, you should create one with the following contents:@tailwind base; @tailwind components; @tailwind utilities;
You should then remove
/app/tailwind.css
from your.gitignore
file since it now contains source code rather than processed output.You can then update your
package.json
scripts to remove any usage oftailwindcss
since Remix handles this automatically. For example, if you had followed the original setup guide:{ // ... "scripts": { - "build": "run-s \"build:*\"", + "build": "remix build", - "build:css": "npm run generate:css -- --minify", - "build:remix": "remix build", - "dev": "run-p \"dev:*\"", + "dev": "remix dev", - "dev:css": "npm run generate:css -- --watch", - "dev:remix": "remix dev", - "generate:css": "npx tailwindcss -o ./app/tailwind.css", "start": "remix-serve build" } // ... }
- fix(react,dev): dev chunking and refresh race condition (#6201)
- Revalidate loaders only when a change to one is detected. (#6135)
- short circuit links and meta for routes that are not rendered due to errors (#6107)
- don't warn about runtime deprecation warnings in production (#4421)
- Update Remix for React Router no longer relying on
useSyncExternalStore
(#6121) - Fix false-positive resource route identification if a route only exports a boundary (#6125)
- better type discrimination when unwrapping loader return types (#5516)
- Updated dependencies:
-
Deprecated
fetcher.type
andfetcher.submission
for Remix v2 (#5691) -
We have made a few changes to the API for route module
meta
functions when using thefuture.v2_meta
flag. These changes are only breaking for users who have opted in. (#5746)V2_HtmlMetaDescriptor
has been renamed toV2_MetaDescriptor
- The
meta
function's arguments have been simplifiedparentsData
has been removed, as each route's loader data is available on thedata
property of its respectivematch
object// before export function meta({ parentsData }) { return [{ title: parentsData["routes/some-route"].title }]; } // after export function meta({ matches }) { return [ { title: matches.find((match) => match.id === "routes/some-route") .data.title, }, ]; }
- The
route
property on route matches has been removed, as relevant match data is attached directly to the match object// before export function meta({ matches }) { const rootModule = matches.find((match) => match.route.id === "root"); } // after export function meta({ matches }) { const rootModule = matches.find((match) => match.id === "root"); }
- Added support for generating
<script type='application/ld+json' />
and meta-related<link />
tags to document head via the routemeta
function when using thev2_meta
future flag
-
Added deprecation warning for
v2_normalizeFormMethod
(#5863) -
Added a new
future.v2_normalizeFormMethod
flag to normalize the exposeduseNavigation().formMethod
as an uppercase HTTP method to align with the previoususeTransition
behavior as well as thefetch()
behavior of normalizing to uppercase HTTP methods. (#5815)- When
future.v2_normalizeFormMethod === false
,useNavigation().formMethod
is lowercaseuseFetcher().formMethod
is uppercase
- When
future.v2_normalizeFormMethod === true
:useNavigation().formMethod
is uppercaseuseFetcher().formMethod
is uppercase
- When
-
Added deprecation warning for normalizing
imagesizes
&imagesrcset
properties returned from the routelinks
function. Both properties should be in camelCase (imageSizes
/imageSrcSet
) to align with their respective JavaScript properties. (#5706) -
Added deprecation warning for
CatchBoundary
in favor offuture.v2_errorBoundary
(#5718) -
Added experimental support for Vanilla Extract caching, which can be enabled by setting
future.unstable_vanillaExtract: { cache: true }
inremix.config
. This is considered experimental due to the use of a brand new Vanilla Extract compiler under the hood. In order to use this feature, you must be using at leastv1.10.0
of@vanilla-extract/css
. (#5735)
- Bumped React Router dependencies to the latest version. See the release notes for more details. (
e14699547
) - Added type deprecations for types now in React Router (#5679)
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.14.3.
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.14.2.
- Deprecate
useTransition
in favor ofuseNavigation
(#5687) - Memoize return value of
useMatches
(#5603)
- Hot Module Replacement and Hot Data Revalidation (#5259)
- Requires
unstable_dev
future flag to be enabled - HMR provided through React Refresh
- Features:
- HMR for component and style changes
- HDR when loaders for current route change
- Known limitations for MVP:
- Only implemented for React via React Refresh
- No
import.meta.hot
API exposed yet - Revalidates all loaders on route when loader changes are detected
- Loader changes do not account for imported dependencies changing
- Requires
- Remove duplicate manifest imports (#5534)
- Ensure types for fetchers always include
form*
submission fields (#5476) - Sync
FutureConfig
interface between packages (#5398) - Updated dependencies:
@remix-run/[email protected]
[email protected]
- Add built-in support for PostCSS via the
future.unstable_postcss
feature flag (#5229) - Add built-in support for Tailwind via the
future.unstable_tailwind
feature flag (#5229)
- Bump React Router dependencies to the latest version. See the release notes for more details. (#5389)
- Improve efficiency of route manifest-to-tree transformation (#4748)
- Added better detection for absolute urls in
<Link>
and<NavLink>
components (#5390)
- Added a new development server available in the Remix config under the
unstable_dev
flag. See the release notes for a full description. (#5133) - You can now configure the client-side socket timeout via the new
timeoutMs
prop on<LiveReload />
(#4036)
<Link to>
can now accept absolute URLs. When theto
value is an absolute URL, the underlying anchor element will behave as normal, and its URL will not be prefetched. (#5092)- Bump React Router dependencies to the latest version. See the release notes for more details. (#5242)
- Added support for
unstable_useBlocker
andunstable_usePrompt
from React Router (#5151)
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.11.1.
- Added support for Vanilla Extract via the
unstable_vanillaExtract
future flag. IMPORTANT: Features marked withunstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#5040) - Add support for CSS side-effect imports via the
unstable_cssSideEffectImports
future flag. IMPORTANT: Features marked withunstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#4919) - Add support for CSS Modules via the
unstable_cssModules
future flag. IMPORTANT: Features marked withunstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#4852)
-
Fix v2
meta
to ensure meta is rendered from the next route in the tree if nometa
export is included in a leaf route (#5041) -
Ensure
useFetcher
is stable across re-renders in backwards-compatibility layer (#5118) -
Added the
v2_errorBoundary
future flag to opt into the next version of Remix'sErrorBoundary
behavior. This removes the separateCatchBoundary
andErrorBoundary
and consolidates them into a singleErrorBoundary
, following the logic used byerrorElement
in React Router. You can then useisRouteErrorResponse
to differentiate between thrownResponse
/Error
instances. (#4918)// Current (Remix v1 default) import { useCatch } from "@remix-run/react"; export function CatchBoundary() { const caught = useCatch(); return ( <p> {caught.status} {caught.data} </p> ); } export function ErrorBoundary({ error }) { return <p>{error.message}</p>; }
// Using future.v2_errorBoundary import { isRouteErrorResponse, useRouteError } from "@remix-run/react"; export function ErrorBoundary() { const error = useRouteError(); return isRouteErrorResponse(error) ? ( <p> {error.status} {error.data} </p> ) : ( <p>{error.message}</p> ); }
-
Introduces the
defer()
API from@remix-run/router
with support for server-rendering and HTTP streaming. This utility allows you to defer values returned fromloader
functions by returning promises instead of resolved values. This has been refered to as "sending a promise over the wire". (#4920)Informational Resources:
- https://gist.github.com/jacob-ebey/9bde9546c1aafaa6bc8c242054b1be26
- https://github.com/remix-run/remix/blob/main/decisions/0004-streaming-apis.md
Documentation Resources (better docs specific to Remix are in the works):
- Fetchers should persist data through reload/resubmit (#5065)
- Update babel config to transpile down to node 14 (#5047)
- Update Remix to use new data APIs introduced in React Router v6.4 (#4900)
- Added new hooks from React Router
- Update
@remix-run/react
to useRouter
from[email protected]
(#4731) - Allow pass-through props to be passed to the script rendered by
ScrollRestoration
(#2879) - Fixed a problem with
<LiveReload>
and Firefox infinitely reloading the page. (#4725)
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.8.2.
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.8.1.
- Importing functions and types from the
remix
package is deprecated, and all (#3284) exported modules will be removed in the next major release. For more details, see the release notes for 1.4.0 where these changes were first announced. - Added support for a new route
meta
API to handle arrays of tags instead of an object. For details, check out the RFC. (#4610)
- Ensure route modules are loaded even in failure cases. This addresses a long standing issue where you would end up in your root catch boundary if a form transition to another route threw. This no longer occurs, and you end up in the contextual boundary you'd expect. (#4611)
- Fixed a regression in the browser build for browsers that don't support the nullish coalescing operator (#4561)
- Make sure namespaced Open Graph and
fb:app_id
meta data renders the correct attributes on<meta>
tags (#4445)
- Ignore pathless layout routes in action matches (#4376)
- You can now infer the type of the
.data
property ofuseFetcher
from the return type of yourloader
andaction
functions (#4392) - Fixed a bug in
<Form>
that prevented the correct method from being called with non-POST
submissions (b52507861
)
- Ensure that
<Form />
respects theformMethod
attribute set on the submitter element (#4053)
- Remove unused
type-fest
dependency (#4246) - Preserve
?index
for fetcher get submissions to index routes (#4238)
- Properly locked the dependency on
react-router-dom
to version 6.3.0 (#4203) - Fixed a bug with
GET
form submissions to ensure they replace the current search params, which tracks with the browser's behavior (#4046)
- We've added a new type:
SerializeFrom
. This is used to infer the (#4013) JSON-serialized return type of loaders and actions.
- Unblock hydration via async module scripts. (#3918)
- Previously, if an
action
was omitted from<Form>
oruseFormAction
, the action value would default to"."
. This is incorrect, as"."
should resolve based on the current path, but an empty action resolves relative to the current URL (including the search and hash values). We've fixed this to differentiate between the two, meaning that the resolved action will preserve the full URL. (#3697) - Enhanced some types to work more seamlessly with React 18 (#3917)
- Added a subscribe method to the transition manager, which allows subscribing and unsubscribing for React 18 strict mode compliance (#3964)
- Fix inferred types for
useLoaderData
anduseActionData
to preservenull
value types (#3879)
- Allow the
ReadonlyArray
type inSerializeType
for action and loader data (#3774) - Support undefined unions as optional keys in types returned from
useLoaderData
anduseActionData
(#3766)
-
We enhanced the type signatures of
loader
/action
anduseLoaderData
/useActionData
to make it possible to infer the data type from return type of its related server function.To enable this feature, you will need to use the
LoaderArgs
type from your Remix runtime package instead of typing the function directly:- import type { LoaderFunction } from "@remix-run/[runtime]"; + import type { LoaderArgs } from "@remix-run/[runtime]"; - export const loader: LoaderFunction = async (args) => { - return json<LoaderData>(data); - } + export async function loader(args: LoaderArgs) { + return json(data); + }
Then you can infer the loader data by using
typeof loader
as the type variable inuseLoaderData
:- let data = useLoaderData() as LoaderData; + let data = useLoaderData<typeof loader>();
The API above is exactly the same for your route
action
anduseActionData
via theActionArgs
type.With this change you no longer need to manually define a
LoaderData
type (huge time and typo saver!), and we serialize all values so thatuseLoaderData
can't return types that are impossible over the network, such asDate
objects or functions. -
Add
WebSocket
reconnect toLiveReload