跳到主要內容
版本:6.x

伺服器渲染

這個指南將說明如何使用 React Native for Web 和 React Navigation 為 React Native app 進行伺服器渲染。我們將涵蓋下列案例

  1. 根據要求 URL 渲染正確的配置
  2. 根據焦點畫面設定適當的頁面元資料

先決

在遵循指南之前,請確保 app 已在伺服器上順利渲染。為此,您需要確保以下事項

  • 編譯並發佈至 npm 時,您使用的所有依賴項皆已編譯,讓您不會在 Node.js 上得到語法錯誤。
  • Node.js 已設定為可以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,你可以使用 context 引數中的 pathsearch 屬性

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 畫面中使用內容。在此,我們新增一個包含 404 值的 code 屬性,以標示找不到畫面

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 取得目前顯示畫面的選項。
  • 使用情境附加更多資訊,例如狀態碼。