伺服器渲染
這個指南將說明如何使用 React Native for Web 和 React Navigation 為 React Native app 進行伺服器渲染。我們將涵蓋下列案例
- 根據要求 URL 渲染正確的配置
- 根據焦點畫面設定適當的頁面元資料
先決
在遵循指南之前,請確保 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 引數中的 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
畫面中使用內容。在此,我們新增一個包含 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
取得目前顯示畫面的選項。 - 使用情境附加更多資訊,例如狀態碼。