root
このコンテンツはまだ日本語訳がありません。
根路由
根
路由(app/root.tsx
)是 Remix 应用程序中唯一必需的路由,因为它是 routes/
目录中所有路由的父级,并负责呈现根 <html>
文档。
除此之外,它基本上就像任何其他路由一样,并支持所有标准路由导出:
headers
meta
links
loader
clientLoader
action
clientAction
default
ErrorBoundary
HydrateFallback
handle
shouldRevalidate
由于根路由管理您的文档,因此它是呈现 Remix 提供的少数文档级
组件的合适位置。这些组件将在您的根路由中使用一次,它们包括 Remix 为正确呈现您的页面而计算或构建的所有内容。
import type { LinksFunction } from "@remix-run/node"; // or cloudflare/denoimport { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration,} from "@remix-run/react";
import globalStylesheetUrl from "./global-styles.css";
export const links: LinksFunction = () => { return [{ rel: "stylesheet", href: globalStylesheetUrl }];};
export default function App() { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
{/* All `meta` exports on all routes will render here */} <Meta />
{/* All `link` exports on all routes will render here */} <Links /> </head> <body> {/* Child routes render here */} <Outlet />
{/* Manages scroll position for client-side transitions */} {/* If you use a nonce-based content security policy for scripts, you must provide the `nonce` prop. Otherwise, omit the nonce prop as shown here. */} <ScrollRestoration />
{/* Script tags go here */} {/* If you use a nonce-based content security policy for scripts, you must provide the `nonce` prop. Otherwise, omit the nonce prop as shown here. */} <Scripts />
{/* Sets up automatic reload when you change code */} {/* and only does anything during development */} {/* If you use a nonce-based content security policy for scripts, you must provide the `nonce` prop. Otherwise, omit the nonce prop as shown here. */} <LiveReload /> </body> </html> );}
布局导出
由于根路由管理所有路由的文档,因此它还支持额外的可选布局
导出。您可以在此 RFC 中阅读详细信息,但布局路由有两个用途:
- 避免在根组件、
HydrateFallback
和ErrorBoundary
中重复文档 /应用外壳
- 避免在根组件 /
HydrateFallback
/ErrorBoundary
之间切换时 React 重新挂载应用外壳元素,如果 React 从<Links>
组件中删除并重新添加<link rel="stylesheet">
标签,则可能导致 FOUC。
import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration,} from "@remix-run/react";
export function Layout({ children }) { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <Meta /> <Links /> </head> <body> {/* children will be the root Component, ErrorBoundary, or HydrateFallback */} {children} <Scripts /> <ScrollRestoration /> <LiveReload /> </body> </html> );}
export default function App() { return <Outlet />;}
export function ErrorBoundary() { const error = useRouteError();
if (isRouteErrorResponse(error)) { return ( <> <h1> {error.status} {error.statusText} </h1> <p>{error.data}</p> </> ); }
return ( <> <h1>Error!</h1> <p>{error?.message ?? "Unknown error"}</p> </> );}
关于 Layout
组件中的 useLoaderData
的说明
不允许在 ErrorBoundary
组件中使用 useLoaderData
,因为它旨在用于快乐路径路由渲染,并且其类型有一个内置假设,即 loader
成功运行并返回了某些内容。该假设在 ErrorBoundary
中不成立,因为可能是 loader
抛出了边界并触发了边界!为了访问 ErrorBoundary
中的加载器数据,您可以使用 useRouteLoaderData
,这考虑到了加载器数据可能为未定义
。
由于您的 Layout
组件在成功和错误流程中均有使用,因此同样的限制也适用。如果您需要根据请求是否成功在 Layout
中分叉逻辑,则可以使用 useRouteLoaderData("root")
和 useRouteError()
。
由于您的
<Layout>
组件用于渲染ErrorBoundary
,因此您应该非常谨慎,以确保您可以渲染ErrorBoundary
而不会遇到任何渲染错误。如果您的Layout
在尝试渲染边界时抛出另一个错误,则无法使用它,并且您的 UI 将回退到非常小的内置默认ErrorBoundary
。
// "app/root.tsx"export function Layout({ children,}: { children: React.ReactNode;}) { const data = useRouteLoaderData("root"); const error = useRouteError();
return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <Meta /> <Links /> <style dangerouslySetInnerHTML={{ __html: ` :root { --themeVar: ${ data?.themeVar || defaultThemeVar } } `, }} /> </head> <body> {data ? ( <Analytics token={data.analyticsToken} /> ) : null} {children} <ScrollRestoration /> <Scripts /> </body> </html> );}
参见: