基于React+Redux的SSR实现方法(2)

你看到,我们使用 componentWillMount 来发送 fetchUsers 请求, componentDidMount 为什么不能用呢? 主要原因是 componentDidMount 在服务端渲染过程中并不会执行。

fetchUsers 是一个异步函数,它通过Fetch API请求数据。当数据返回时,会派发 users_fetch 动作,从而通过 reducer 重新计算状态,而我们的 <App /> 由于连接到 Redux 从而被重新渲染。

// client.js import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import App from './App.jsx'; import createStore from './redux/store'; ReactDOM.render( <Provider store={ createStore() }><App /></Provider>, document.querySelector('#content') );

运行Node Server

为了演示方便,我们首选Express作为http服务器。

// server.js import express from 'express'; const app = express(); // Serving the content of the "build" folder. Remember that // after the transpiling and bundling we have: // // build // ├── client // ├── server // │ └── server.js // └── bundle.js app.use(express.static(__dirname + '/../')); app.get('*', (req, res) => { res.set('Content-Type', 'text/html'); res.send(` <html> <head> <title>App</title> </head> <body> <div></div> <script src="https://www.jb51.net/bundle.js"></script> </body> </html> `); }); app.listen( 3000, () => console.log('Example app listening on port 3000!') );

有了这个文件,我们可以运行 npm run start 并访问 :3000 。我们看到数据获取成功,并成功的显示了。

服务端渲染

目前为止,我们的服务端仅仅是返回了一个 html 骨架,而所有交互全在客户端完成。浏览器需要先下载 bundle.js 后执行。而服务端渲染的作用就是在服务器上执行所有操作并发送最终标记,而不是把所有工作交给浏览器执行。 React 足够的聪明,能够识别出这些标记。

还记得我们在客户端做的以下事情吗?

import ReactDOM from 'react-dom'; ReactDOM.render( <Provider store={ createStore() }><App /></Provider>, document.querySelector('#content') );

服务端几乎相同:

import ReactDOMServer from 'react-dom/server'; const markupAsString = ReactDOMServer.renderToString( <Provider store={ store }><App /></Provider> );

我们使用了相同的组件 <App /> 和 store ,不同之处在于它返回的是一个字符串,而不是虚拟DOM。

然后将这个字符串加入到 Express 的响应里面,所以服务端代码为:

const store = createStore(); const content = ReactDOMServer.renderToString( <Provider store={ store }><App /></Provider> ); app.get('*', (req, res) => { res.set('Content-Type', 'text/html'); res.send(` <html> <head> <title>App</title> </head> <body> <div>${ content }</div> <script src="https://www.jb51.net/bundle.js"></script> </body> </html> `); });

如果重新启动服务器并打开相同的 :3000 ,我们将看到以下响应:

<html> <head> <title>App</title> </head> <body> <div><div data-reactroot=""></div></div> <script src="https://www.jb51.net/bundle.js"></script> </body> </html>

我们的页面中确实有一些内容,但它只是 <div data-reactroot=""></div> 。这并不意味着程序出错了。这绝对是正确的。 React 确实呈现了我们的页面,但它只呈现静态内容。在我们的组件中,我们在获取数据之前什么都没有,数据的获取是一个异步过程,在服务器上呈现时,我们必须考虑到这一点。这就是我们的任务变得棘手的地方。这可以归结为我们的应用程序在做什么。在本例中,客户端代码依赖于一个特定的请求,但如果使用 redux-saga 库,则可能是多个请求,或者可能是一个完整的root saga。我意识到处理这个问题的两种方法:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/1dcb7b73cd88ec7b86896d444340671c.html