CSS-in-JS
警告: 需要运行时 JavaScript 的 CSS-in-JS 库目前不支持在服务器组件中使用。与新的 React 功能(如服务器组件和流式传输)一起使用 CSS-in-JS 需要库作者支持最新版本的 React,包括并发渲染.
我们正在与 React 团队合作开发上游 API,以处理支持 React 服务器组件和流式架构的 CSS 和 JavaScript 资源。
以下库在app目录中的客户端组件中受支持(按字母顺序排列):
ant-designchakra-ui@fluentui/react-componentskuma-ui@mui/material@mui/joypandacssstyled-jsxstyled-componentsstylextamaguitss-reactvanilla-extract
目前正在进行以下支持工作:
您需要知道: 我们正在测试不同的 CSS-in-JS 库,并将为支持 React 18 功能和/或 app 目录的库添加更多示例。
如果您想为服务器组件设置样式,我们建议使用CSS Modules或其他输出 CSS 文件的解决方案,如 PostCSS 或Tailwind CSS.
在app中配置 CSS-in-JS
配置 CSS-in-JS 是一个包含三个步骤的可选的过程,包括:
- 一个 ** 样式注册表**用于收集所有渲染时的 CSS 规则。
- 新的
useServerInsertedHTMLhook 用于在任何可能使用规则的内容前添加规则。 - 在初始服务器端渲染期间使用样式注册表包装您的应用程序的客户端组件。
styled-jsx
在客户端组件中使用 styled-jsx需要使用v5.1.0。首先,创建一个新的注册表:
"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { StyleRegistry, createStyleRegistry } from "styled-jsx";
export default function StyledJsxRegistry({
children,
}: {
children: React.ReactNode;
}) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [jsxStyleRegistry] = useState(() => createStyleRegistry());
useServerInsertedHTML(() => {
const styles = jsxStyleRegistry.styles();
jsxStyleRegistry.flush();
return <>{styles}</>;
});
return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>;
}
"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { StyleRegistry, createStyleRegistry } from "styled-jsx";
export default function StyledJsxRegistry({ children }) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [jsxStyleRegistry] = useState(() => createStyleRegistry());
useServerInsertedHTML(() => {
const styles = jsxStyleRegistry.styles();
jsxStyleRegistry.flush();
return <>{styles}</>;
});
return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>;
}
然后, 用注册表包装您的根布局:
import StyledJsxRegistry from "./registry";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
);
}
import StyledJsxRegistry from "./registry";
export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
);
}
查看示例.
样式组件
下面是配置styled-components@6或更新版本的示例:
First, enable styled-components in next.config.js.
module.exports = {
compiler: {
styledComponents: true,
},
};
然后, 使用styled-components API 创建一个全局注册组件,以收集在渲染期间生成的所有 CSS 样式规则,并创建一个函数返回这些规则。然后使用useServerInsertedHTML hook 将注册表中收集的样式注入到根布局中的<head>HTML 标签中。
"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
export default function StyledComponentsRegistry({
children,
}: {
children: React.ReactNode;
}) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement();
styledComponentsStyleSheet.instance.clearTag();
return <>{styles}</>;
});
if (typeof window !== "undefined") return <>{children}</>;
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
);
}
"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
export default function StyledComponentsRegistry({ children }) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement();
styledComponentsStyleSheet.instance.clearTag();
return <>{styles}</>;
});
if (typeof window !== "undefined") return <>{children}</>;
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
);
}
使用样式注册组件包装根布局的 children:
import StyledComponentsRegistry from "./lib/registry";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
);
}
import StyledComponentsRegistry from "./lib/registry";
export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
);
}
查看示例。
您需要知道:
- 在服务器渲染期间,样式将被提取到全局注册表并刷新到 HTML 的
<head>中。这确保了样式规则在任何可能使用它们的内容之前被放置。未来,我们可能会使用即将推出的 React 功能来确定注入样式的位置。- 在流式传输期间,每个块的样式将被收集并附加到现有样式中。客户端水合完成后,
styled-components将像往常一样接管并注入任何进一步的动态样式。- 我们专门在树的顶层使用客户端组件作为样式注册表,因为这样提取 CSS 规则更有效。它避免了在后续服务器 渲染中重新生成样式,并防止它们在服务器组件负载中被发送。
- 对于需要配置 styled-components 编译的各个属性的高级用例,您可以阅读我们的Next.js styled-components API reference了解更多信息。