如何在 React 应用服务器上渲染 CSS

介绍

Next.js(React)和 Nuxt.js(Vue)有助于简化向服务器渲染应用程序视图的过程。

您仍然需要一个解决方案来渲染您的 React 组件中的 CSS,以适应开发方式;您还需要一个解决方案来渲染 CSS 在服务器上,以便风格可用。

在本文中,我们将讨论渲染 CSS 的挑战,然后在 Next.js 项目中在服务器上使用styled-componentsstyled-jsx

前提条件

要完成本教程,您将需要:

本教程已通过 Node v16.2.0、npm v7.14.0、react v17.0.2、react-dom v17.0.2、next v10.2.3 和styled-compnents v5.3.0 进行验证。

在React中理解风格模式

在 React 中写 CSS 的几种常见方法都是有效的. 根据您的情况,您正在以以下方式应用 React 应用程序的样式:

全球风格

_Global styles 是包含本地或内容交付网络(CDN)托管的样式表的模式。

这里有一个例子:

1<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />

这是不太受欢迎的造型模式,因为它不鼓励元件的重复使用,也不鼓励风格的构成。

这些 CSS 规则不直接涵盖特定元素或组件,而当组件以无法预料的方式进行导入、嵌入或扩展时,出现冲突的可能性很高。

然而,有一些情况,如字体包含和CSS重置和默认设置,您可以在全球范围内包括风格。

内部风格

inline styles 直接应用于 DOM 元素或 React 组件,使用 React 属性风格

这里有一个例子:

1const titleStyle = {
2  fontSize: '4rem';
3  lineHeight: '1.6';
4  color: '#222';
5}
6
7<h1 style={titleStyle} {...props}>{props.children}<h1>

这种模式鼓励风格和组件组成以及重复使用。

然而,内线风格不能为您提供一种方法来处理与假类类和目标假类元素的焦点状态的波动,对于更大的和复杂的项目,您可能需要一个更强大的解决方案。

元素风格

component styles 鼓励重复使用,并帮助您更好地构成风格和组件. 您将需要一个实用程序或库来帮助您实现这一目标。

styled-components是实现CSS-in-JS的一种流行的解决方案,它们是线性组件风格,但具有更多的能力来做复杂(假冒)选择,嵌套等事情。

步骤1 - 设置项目

要开始,打开终端并为您的项目创建一个新的文件夹:

1mkdir css-ssr-next-example

接下来,更改到新项目目录:

1cd css-ssr-next-example

然后运行以下命令来初始化它:

1npm init -y

这将创建一个package.json文件,您将使用它来跟踪依赖。

然后,安装 Next.js、React 和 React DOM:

1npm install [email protected] [email protected] react-dom17.0.2

此时,您将有一个新的项目,包括 Next.js、React 和 React DOM。

<$>[注] 注: 自发布以来,创建 Next.js 项目的现代化方法可以使用 create-next-app

现在,更新「package.json」以启动使用「dev」脚本的 Next.js 应用:

 1[label package.json]
 2{
 3  "name": "css-ssr-next-example",
 4  "version": "1.0.0",
 5  "description": "",
 6  "main": "index.js",
 7  "scripts": {
 8    "test": "echo \"Error: no test specified\" && exit 1",
 9    "dev": "next"
10  },
11  "keywords": [],
12  "author": "",
13  "license": "ISC",
14  "dependencies": {
15    "next": "^10.2.3",
16    "react": "^17.0.2",
17    "react-dom": "^17.0.2"
18  }
19}

然后,创建一个页面目录:

1mkdir pages

在此目录中,添加一个包含以下内容的 index.js 文件:

1[label pages/index.js]
2import React from 'react';
3
4const Index = () => <h1>Hi, new Next.js project</h1>;
5
6export default Index;

现在运行dev脚本来启动服务器:

1npm run dev

如果你在网页浏览器中打开localhost:3000,你会注意到:

1[secondary_label Output]
2Hi, new Next.js project

首先,使用下面的Head组件使用normalize.css来规范样式:

 1[label pages/index.js]
 2import React from 'react';
 3import Head from 'next/head';
 4
 5const Index = () =>
 6  <div>
 7    <Head>
 8      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
 9      <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" />
10    </Head>
11    <h1>Hi, new Next.js project</h1>
12  </div>;
13
14export default Index;

接下来,在您的 Next.js 项目的根上创建一个静态文件夹:

1mkdir static

在此目录中,添加一个包含以下 CSS 内容的 base.css 文件:

1[label static/base.css]
2body {
3  font-family: 'Raleway', sans-serif;
4  color: #222;
5}

在索引页面中导入 base.css 文件:

 1[label pages/index.js]
 2// ...
 3
 4    <Head>
 5      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
 6      <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" />
 7      <link rel="stylesheet" href="/static/base.css" />
 8    </Head>
 9
10// ...

在浏览器中,字体将可见地从默认字体更改为Raleway。

此时,你有一个 Next.js 项目,具有全球风格。

步骤2 – 使用风格化的组件

让我们使用样式化组件库来样式化组件。

首先,安装styled-components:

1npm install [email protected]

接下来,创建一个组件目录:

1mkdir components

在此目录中,添加一个 Button.js 文件,并更新该文件如下:

 1[label components/Button.js]
 2import React from 'react';
 3import styled from 'styled-components';
 4
 5const ButtonBase = (props) => <button {...props}>{props.children}</button>
 6const Button = styled(ButtonBase)`
 7  /* Rectangle 2: */
 8  background: #0077E2;
 9  box-shadow: 0 2px 7px 0 rgba(120,137,149,0.25);
10  border-radius: 3px;
11  text-transform: uppercase;
12  padding: 10px;
13  color: #fff;
14  border: #0077E2;
15`
16
17export default Button;

我们正在使用作为样式化导入的样式化组件来样式化一个按钮ButtonBase返回按钮的骨骼,而Button返回一个具有样式化的ButtonBase的组件。

在索引页面中导入并使用按钮组件:

 1[label index.js]
 2import React from 'react';
 3import Head from 'next/head';
 4import Button from '../components/Button'
 5
 6const Index = () => <div>
 7  <Head>
 8    ....
 9  </Head>
10  <h1>Hi, new Next.js project</h1>
11  <Button>Clicker</Button>
12</div>;
13
14export default Index;

保存更改,并在浏览器中观察应用程序. 文本下方将有一个新的风格按钮。

然而,经过艰难的更新,按钮不再像预期的样式。

按钮风格似乎不存在,但以某种方式,基本风格是完整的. 使用 Web 开发人员工具检查页面源。

内容被渲染到服务器,但它不会显示与按钮有关的页面上的任何风格,另一方面,我们可以从应用的字体风格中观察到,我们知道外部文件被成功渲染到服务器。

那么,组件风格有什么不对劲呢?看看控制台:

1[secondary_label Output]
2Warning: Prop `className` did not match. Server: "sc-gtsrHT kbmjhF" Client: "sc-bdnxRM kbyRfM"

您可以看到类名称中显示错误的错误,这是因为当您重新加载时,内容首先从服务器上获取。

不幸的是,风格化组件不会被渲染到服务器上,这使得它们在当时不可用。

<$>[注] 注: 自发布以来,‘styled-components’ 支持 服务器侧渲染

您还可以参阅 Next.js 的 with-styled-components 示例

让我们来看看一个解决方案。

步骤 3 – 使用 Styled JSX

Next.js 的工作团队引入了一个名为 styled-jsx的库,以帮助控制缓解此问题。

它已经配备了 Next.js,所以您不需要安装任何东西。

重新定义按钮组件并修改它以使用styled-jsx:

 1[label components/Button.js]
 2import React from 'react';
 3
 4const Button = props => (
 5  <button {...props}>
 6    {props.children}
 7    <style jsx>{`
 8      background: #0077e2;
 9      box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25);
10      border-radius: 3px;
11      text-transform: uppercase;
12      padding: 10px;
13      color: #fff;
14      border: #0077e2;
15    `}</style>
16  </button>
17);
18
19export default Button;

在我们想要样式化的组件中关闭根元素的标签之前,您可以创建一个具有jsx属性的风格元素。在风格元素中,打开一个包含模板字符串的弯曲字符串。

您也可以在「styled-jsx」中使用选择器,如果您的组件不由一个元素组成:

 1[label components/TitleAndButton.js]
 2import React from 'react';
 3
 4const TitleAndButton = props => (<div {...props}>
 5  <h1 className="title">Hi Title</h1>
 6  <button>Clicker</button>
 7  <style jsx>{`
 8    h1.title {
 9      color: #222
10    }
11    button {
12      background: #0077e2;
13      box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25);
14      border-radius: 3px;
15      text-transform: uppercase;
16      padding: 10px;
17      color: #fff;
18      border: #0077e2;
19    }
20  `}</style>
21</div>);
22
23export default TitleAndButton;

现在,您可以在索引页面中导入和使用TitleAndButton组件,这两种元素都将按预期进行定制。

<$>[注] 注: 您也可以参阅 Next.js 的 with-styled-jsx 示例

'styled-jsx' 是 Next.js 项目中向服务器渲染风格的一种方法。

结论

在本文中,您了解了 CSS 渲染的挑战,然后在 Next.js 项目中在服务器上使用了styled-componentsstyled-jsx

如果您想了解更多关于 Next.js 的信息,请尝试我们的技术谈话 Getting Started with Next.js,或查看 我们的 Next.js 主题页面以了解练习和编程项目。

Published At
Categories with 技术
comments powered by Disqus