详解react服务端渲染(同构)的方法

详解React服务端渲染(同构)的方法

React的服务端渲染(SSR)或同构应用是指将React组件在服务器端进行渲染,将渲染结果发送到客户端,客户端将不再需要JavaScript来根据React组件生成DOM,而直接使用服务器端渲染的结果。同构应用的好处在于可以提高前端应用的性能和SEO。下面将会介绍如何进行React服务端渲染。

1.创建基础项目

首先建立一个基础项目来进行React服务端渲染。在项目根目录下执行以下命令:

$ npm init -y
$ npm install --save react react-dom express

创建一个简单的React组件,并编写服务器端渲染代码并返回给客户端显示。

// index.js
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import express from 'express';

const app = express();

const HelloWorld = () => {
  return (
    <div>
      <h1>Hello world!</h1>
      <p>This is my first server-side rendered React.</p>
    </div>
  )
}

app.get('/', (req, res) => {
  const html = ReactDOMServer.renderToString(<HelloWorld />);
  res.send(`
    <html>
      <head>
        <title>React SSR Demo</title>
      </head>
      <body>
        <div id="root">${html}</div>
        <script src="/bundle.js"></script>
      </body>
    </html>
  `);
});

app.listen(3000, () => {
  console.log('server started on port 3000');
});

在浏览器中打开http://localhost:3000,应该看到渲染出了“Hello world”和“This is my first server-side rendered React”信息。

2.使用React Router进行路由

React Router是管理应用程序路由的最流行的库之一。使用React Router进行服务器端渲染有两种方法:StaticRouter和BrowserRouter。StaticRouter用于静态网站,BrowserRouter更适用于web应用。本文使用BrowserRouter。

首先需要更改React组件到路由组件:

// HelloWorld.js
import React from 'react';

const HelloWorld = () => {
  return (
    <div>
      <h1>Hello world!</h1>
      <p>This is my first server-side rendered React.</p>
    </div>
  )
}

export default HelloWorld;
// App.js
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import HelloWorld from './HelloWorld';

const App = () => {
  return (
    <Switch>
      <Route exact path="/" component={HelloWorld} />
      <Route render={() => <div>404 Not Found</div>} />
    </Switch>
  );
};

export default App;

接下来更改服务器端代码,使用React Router渲染组件,并处理嵌套路由情况:

// index.js
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter as Router } from 'react-router-dom';
import express from 'express';

import App from './App';

const app = express();

app.use('/static', express.static('static'));

app.get('*', (req, res) => {
  const context = {};
  const html = ReactDOMServer.renderToString(
    <Router location={req.url} context={context}>
      <App />
    </Router>
  );

  if (context.url) {
    res.redirect(context.url);
  } else {
    res.status(200).send(`
      <html>
        <head>
          <title>React SSR Demo</title>
        </head>
        <body>
          <div id="root">${html}</div>
          <script src="/static/bundle.js"></script>
        </body>
      </html>
    `);
  }
});

app.listen(3000, () => {
  console.log('server started on port 3000');
});

3.使用Redux控制组件状态

当你的React组件需要依赖一些异步数据时,通常会用到Redux。这时候,需要将Redux store传递给服务器端渲染的React组件。

首先需要安装Redux:

$ npm install --save redux react-redux redux-thunk

下面是更新后的App.js:

// App.js
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';
import HelloWorld from './HelloWorld';

const App = () => {
  return (
    <Provider store={store}>
      <Switch>
        <Route exact path="/" component={HelloWorld} />
        <Route render={() => <div>404 Not Found</div>} />
      </Switch>
    </Provider>
  );
};

export default App;

store.js文件如下:

// store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const initialState = {};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};

const store = createStore(reducer, applyMiddleware(thunk));

export default store;

在服务器端渲染时需要使用Redux的server-side rendering功能,并使用StoreProvider包装组件:

// index.js
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter as Router } from 'react-router-dom';
import express from 'express';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

const app = express();

app.use('/static', express.static('static'));

app.get('*', (req, res) => {
  const context = {};
  const html = ReactDOMServer.renderToString(
    <Provider store={store}>
      <Router location={req.url} context={context}>
        <App />
      </Router>
    </Provider>
  );

  if (context.url) {
    res.redirect(context.url);
  } else {
    res.status(200).send(`
      <html>
        <head>
          <title>React SSR Demo</title>
        </head>
        <body>
          <div id="root">${html}</div>
          <script src="/static/bundle.js"></script>
        </body>
      </html>
    `);
  }
});

app.listen(3000, () => {
  console.log('server started on port 3000');
});

4.使用Hydrate进行客户端渲染

在服务器端渲染结束后,客户端会重新渲染组件。在这个过程中,需要使用ReactDOM.hydrate()函数,而不是ReactDOM.render()。hydarte()将会尝试重用服务器端渲染后的组件,以便快速呈现静态内容。例如:

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

ReactDOM.hydrate(
  <Provider store={store}>
    <Router>
      <App />
    </Router>
  </Provider>,
  document.getElementById('root')
);

通过上面的步骤,就可以完成React的服务端渲染。

示例1:使用CSS Modules渲染样式

CSS Modules将CSS文件锁定到组件级别,为React组件提供了一种更优美的样式方案。在React应用程序中使用CSS Modules与服务器端渲染的解决方案非常相似:仅需要在服务器渲染期间的CSS中执行css-modules-require-hook并将这个CSS传递到组件级别。

首先需要安装css-loader和css-modules-require-hook:

$ npm install --save-dev css-loader css-modules-require-hook babel-register

更新webpack.config.js文件,以便使用css-loader和css-modules-require-hook提供的抽象:

// webpack.config.js
module.exports = {
  entry: './client.js',
  output: {
    path: __dirname + '/static',
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: '[name]__[local]__[hash:base64:5]'
              },
              onlyLocals: true
            }
          }
        ]
      }
    ]
  }
};

添加以下代码段到index.js:

// index.js
require('css-modules-require-hook')({
  generateScopedName: '[name]__[local]__[hash:base64:5]',
  extensions: ['.css']
});

require('babel-register')({
  extensions: ['.js', '.jsx']
});

在HelloWorld.js中添加样式:

import React from 'react';
import styles from './HelloWorld.css';

const HelloWorld = () => {
  return (
    <div className={styles.hello}>
      <h1>Hello world!</h1>
      <p>This is my first server-side rendered React.</p>
    </div>
  );
};

export default HelloWorld;
.hello {
  color: blue;
}

在客户端组件中只需要简单地将HelloWorld.css导入即可。此时,在服务器端渲染的React组件中,class应该是动态生成的。

示例2:使用React Helmet进行SEO

React Helmet是管理head标签的最流行的库之一。应用程序需要在head标签中包含某些meta,title和link元素,特别是在SEO的方面。

在服务器渲染React组件时,需要使用React Helmet将标记添加到head标签中。在客户端代码中,使用ReactDOM.hydrate()再次渲染React组件,React Helmet会更新head标签。例如:

// HelloWorld.js
import React from 'react';
import Helmet from 'react-helmet';
import styles from './HelloWorld.css';

const HelloWorld = () => {
  return (
    <div className={styles.hello}>
      <Helmet>
        <title>Hello World</title>
        <meta property="og:title" content="Hello World" />
        <meta name="description" content="This is my first server-side rendered React." />
      </Helmet>
      <h1>Hello world!</h1>
      <p>This is my first server-side rendered React.</p>
    </div>
  );
};

在实际应用中,可以根据需要添加更多的meta和link标记。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解react服务端渲染(同构)的方法 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • Java基于正则表达式实现xml文件的解析功能详解

    Java 基于正则表达式提取 XML 数据 在 Java 中,使用正则表达式可以通过字符串匹配的方式提取 XML 文件中所需的信息。本文介绍如何使用 Java 正则表达式提取 XML 数据的完整攻略。 1. 实现思路 XML 文件的结构和数据都是有层次结构的,因此可以使用正则表达式来匹配 XML 标签和属性。实现思路如下: 读取 XML 文件,将其转化为字符…

    node js 2023年6月8日
    00
  • Node.js中的流(Stream)介绍

    Node.js中的流(Stream)介绍 在 Node.js 中,Stream 是一种处理流式数据的接口。Stream 的本质是数据读写的一种抽象,它们能够以类似将大型数据块分解成小块的方式处理数据。这种数据处理方式允许我们逐块处理数据,而无需等待整个数据文件从磁盘中读取完毕。这在处理大型文件或网络传输中非常有用。 可读流(Readable Stream) …

    node js 2023年6月8日
    00
  • node.js中的fs.realpath方法使用说明

    Node.js中的fs.realpath方法使用说明 什么是fs.realpath方法 在Node.js中,使用fs.realpath(path, options, callback)方法可以将一个传递的路径解析为一个规范的绝对路径。该方法还可以选择性地解析符号链接,并返回最终的路径。 如何使用fs.realpath方法 使用方法 fs.realpath()…

    node js 2023年6月8日
    00
  • 解决vue eslint开发严格模式警告错误的问题

    下面是解决vue eslint开发严格模式警告错误的问题的完整攻略,具体步骤如下: 1. 理解严格模式 在解决问题之前,我们需要先了解一下什么是严格模式。Vue默认启用了ESLint严格模式,用于捕获一些潜在的问题。这种模式下会对一些非规范行为进行报错提示,提高了代码的质量和可维护性。但是对于一些新手或者还不是很熟悉语法的人来说,这些警告可能会显得很繁琐,并…

    node js 2023年6月9日
    00
  • node.JS二进制操作模块buffer对象使用方法详解

    下面我来详细讲解“node.JS二进制操作模块buffer对象使用方法详解”的完整攻略。 什么是Node.js Buffer Node.js Buffer 是一个用于处理二进制数据的全局模块,它可以在前端或者后端中进行使用。Buffer 对象类似于整个缓冲区,它可以存储任何长度的数据,并通过指定的编码格式,将数据转换成字符串或者其他格式。通过读取文件或者网络…

    node js 2023年6月8日
    00
  • 在Windows上安装和配置 Jupyter Lab 作为桌面级应用程序教程

    以下是在Windows上安装和配置 Jupyter Lab 作为桌面级应用程序的完整攻略: 安装 Python 首先,你需要安装 Python。可以从Python官网下载最新版本的Python安装包,选择合适的版本并下载。 下载完成后,双击安装包,按照提示完成安装。 安装完成后,在命令行运行以下命令,验证Python是否安装成功: bash python -…

    node js 2023年6月8日
    00
  • nodejs密码加密中生成随机数的实例代码

    下面详细讲解一下“nodejs密码加密中生成随机数的实例代码”的完整攻略。 1.前言 为了保护用户的密码,我们通常需要将其进行加密处理。在加密的过程中,生成一个随机数是非常重要的。在nodejs中,我们可以使用crypto模块来进行密码加密,并生成一个随机数,从而增强密码安全性。 2.生成随机数的实例代码 我们可以使用crypto模块中的randomByte…

    node js 2023年6月8日
    00
  • 在JavaScript中如何使用宏详解

    当我们使用JavaScript编写大型应用时,经常会遇到需要多次使用同一段代码的情况。在这种情况下,使用宏(Macro)可以减少代码中的重复,使代码更加简洁和易于维护。 使用宏的基本语法 在JavaScript中,使用宏可以通过define方法实现。其基本语法如下: // 定义宏 define(‘宏名’, function() { // 宏代码 }); //…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部