服务器渲染
本指南将介绍如何使用 React Native for Web 和 React Navigation 对您的 React Native 应用程序进行服务器渲染。我们将涵盖以下情况
- 根据请求 URL 渲染正确的布局
- 根据聚焦屏幕设置适当的页面元数据
先决条件
在您遵循本指南之前,请确保您的应用程序已在服务器上正常渲染。为此,您需要确保以下事项
- 您使用的所有依赖项都在发布到 npm 之前编译,这样您就不会在 Node 上遇到语法错误。
- Node 被配置为能够
require
资产文件,例如图像和字体。您可以尝试使用webpack-isomorphic-tools 来做到这一点。 react-native
被别名为react-native-web
。您可以使用babel-plugin-module-resolver 来实现。
渲染应用程序
首先,让我们看一个使用 React Native Web 进行服务器端渲染 的示例,不涉及 React Navigation。
import { AppRegistry } from 'react-native-web';
import ReactDOMServer from 'react-dom/server';
import App from './src/App';
const { element, getStyleElement } = AppRegistry.getApplication('App');
const html = ReactDOMServer.renderToString(element);
const css = ReactDOMServer.renderToStaticMarkup(getStyleElement());
const document = `
<!DOCTYPE html>
<html style="height: 100%">
<meta charset="utf-8">
<meta httpEquiv="X-UA-Compatible" content="IE=edge">
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover"
>
${css}
<body style="min-height: 100%">
<div id="root" style="display: flex; min-height: 100vh">
${html}
</div>
`;
这里,./src/App
是您拥有 AppRegistry.registerComponent('App', () => App)
的文件。
如果您在应用程序中使用 React Navigation,这将渲染您的主页渲染的屏幕。但是,如果您在应用程序中配置了链接,您需要在服务器上为请求 URL 渲染正确的屏幕,以便它与在客户端渲染的内容相匹配。
我们可以使用ServerContainer
通过在 location
属性中传递此信息来做到这一点。例如,使用 Koa,您可以使用来自上下文参数的 path
和 search
属性。
app.use(async (ctx) => {
const location = new URL(ctx.url, 'https://example.org/');
const { element, getStyleElement } = AppRegistry.getApplication('App');
const html = ReactDOMServer.renderToString(
<ServerContainer location={location}>{element}</ServerContainer>
);
const css = ReactDOMServer.renderToStaticMarkup(getStyleElement());
const document = `
<!DOCTYPE html>
<html style="height: 100%">
<meta charset="utf-8">
<meta httpEquiv="X-UA-Compatible" content="IE=edge">
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover"
>
${css}
<body style="min-height: 100%">
<div id="root" style="display: flex; min-height: 100vh">
${html}
</div>
`;
ctx.body = document;
});
您可能还想为搜索引擎、开放图谱等设置正确的文档标题和描述。为此,您可以将 ref
传递给容器,它将为您提供当前屏幕的选项。
app.use(async (ctx) => {
const location = new URL(ctx.url, 'https://example.org/');
const { element, getStyleElement } = AppRegistry.getApplication('App');
const ref = React.createRef<ServerContainerRef>();
const html = ReactDOMServer.renderToString(
<ServerContainer
ref={ref}
location={location}
>
{element}
</ServerContainer>
);
const css = ReactDOMServer.renderToStaticMarkup(getStyleElement());
const options = ref.current?.getCurrentOptions();
const document = `
<!DOCTYPE html>
<html style="height: 100%">
<meta charset="utf-8">
<meta httpEquiv="X-UA-Compatible" content="IE=edge">
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover"
>
${css}
<title>${options.title}</title>
<body style="min-height: 100%">
<div id="root" style="display: flex; min-height: 100vh">
${html}
</div>
`;
ctx.body = document;
});
确保您在屏幕中指定了 title
选项。
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={{ title: 'My profile' }}
/>
处理 404 或其他状态码
当为无效 URL 渲染屏幕 时,我们还应该从服务器返回 404
状态码。
首先,我们需要创建一个上下文,我们将在此上下文中附加状态码。为此,请将以下代码放在一个单独的文件中,我们将在服务器和客户端上导入该文件。
import * as React from 'react';
const StatusCodeContext = React.createContext();
export default StatusCodeContext;
然后,我们需要在 NotFound
屏幕中使用上下文。在这里,我们添加了一个 code
属性,其值为 404
,以表示未找到屏幕。
function NotFound() {
const status = React.useContext(StatusCodeContext);
if (status) {
staus.code = 404;
}
return (
<View>
<Text>Oops! This URL doesn't exist.</Text>
</View>
);
}
如果您需要,您也可以在此对象中附加其他信息。
接下来,我们需要创建一个状态对象,并在服务器上的上下文中传递它。默认情况下,我们将code
设置为200
。然后将该对象传递到StatusCodeContext.Provider
中,它应该用ServerContainer
包装元素。
// Create a status object
const status = { code: 200 };
const html = ReactDOMServer.renderToString(
// Pass the status object via context
<StatusCodeContext.Provider value={status}>
<ServerContainer ref={ref} location={location}>
{element}
</ServerContainer>
</StatusCodeContext.Provider>
);
// After rendering, get the status code and use it for server's response
ctx.status = status.code;
在使用ReactDOMServer.renderToString
渲染应用程序后,如果渲染了NotFound
屏幕,status
对象的code
属性将更新为404
。
您可以对其他状态代码也采用类似的方法,例如,401
表示未授权等。
总结
- 使用
ServerContainer
上的location
属性根据传入的请求渲染正确的屏幕。 - 将
ref
附加到ServerContainer
以获取当前屏幕的选项。 - 使用上下文附加更多信息,例如状态代码。