基于React+Redux的SSR实现

  • 时间:
  • 浏览:1

总结下来有以下几点:

:

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

可能性您想使用本文中讨论的代码,请查看GitHub: answer518/react-redux-ssr

朋友的页面中我我其实有你这种 内容,但它却说我<div data-reactroot=""></div>。这未必原应着程序出错了。这绝对是正确的。React我我其实呈现了朋友的页面,但它只呈现静态内容。在朋友的组件中,朋友在获取数据很久你这种 都这么,数据的获取是有二个 异步过程,在服务器上呈现时,朋友还要考虑到你这种 点。这却说我朋友的任务变得棘手的地方。这可不还可以 归结为朋友的程序在做你这种 。在本例中,客户端代码依赖于有二个 特定的请求,但可能性使用redux-saga库,则可能性是多个请求,可能性可能性是有二个 详细的root saga。我意识到避免你这种 问题图片报告 的两种最好的办法 :

不使用node ./build/server/server.js而使用Nodemon的原应着是,它可不还可以 监控朋友代码中的任何更改,并自动重新启动服务器。你这种 点在开发过程会非常有用。

store.subscribe最好的办法 返回有二个 函数,调用你这种 函数就可不还可以 解除监听

<html>
          <head>
            <title>App</title>
            <style>
              body {
                font-size: 18px;
                font-family: Verdana;
              }
            </style>
          </head>
          <body>
            <div id="content"><div data-reactroot=""><p>Eve Holt</p><p>Charles Morris</p><p>Tracey Ramos</p></div></div>
            <script>
              window.__APP_STATE = {"users":[{"id":4,"first_name":"Eve","last_name":"Holt","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"},{"id":5,"first_name":"Charles","last_name":"Morris","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/stephenmoon/128.jpg"},{"id":6,"first_name":"Tracey","last_name":"Ramos","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/bigmancho/128.jpg"}]};
            </script>
            <script src="/bundle.js"></script>
          </body>
        </html>

为你这种 直接返回的是工厂函数而详细很久createStore(reducer)?这是可能性当朋友在服务器端渲染时,朋友还要有二个 全新的Store实例来避免每个请求。

类似于,朋友使用了Fetch API向后端发出异步请求,而服务端默认是不支持的。朋友还要做的却说我在server.js中将Fetch导入:

目前为止,朋友的服务端仅仅是返回了有二个 html骨架,而所有交互全在客户端完成。浏览器还要先下载bundle.js后执行。而服务端渲染的作用却说我在服务器上执行所有操作并发送最终标记,而详细很久把所有工作交给浏览器执行。React足够的聪明,可不还可以 识别出你这种 标记。

朋友使用客户端API接收异步数据,一旦Store获取到异步数据,朋友将触发ReactDOMServer.renderToString。它会提供给朋友我要我的标记。朋友的Express避免器是那我 的:

有了中间的代码,朋友的组件可能性可不还可以 成功地在服务器端渲染。通过开发者工具,朋友可不还可以 都看发送到浏览器的内容:

在这里还要提的有二个 重点是,一旦朋友想实现服务端渲染,那我 们就还要改变很久的纯客户端编程模式。

代码价值形式如下:

朋友还要保证代码能在服务端正常的运行。类似于,访问Window对象,Node不提供Window对象的访问。

实现的最关键一步却说我创建

服务器端呈现是有二个 有趣励志的话 题。它有却说我优势,并改善了整体用户体验。它很久提升你的单页程序的SEO。但你这种 切未必简单。在大多数具体情况下,还要额外的工具和精心选用的api。

请求去改变应用具体情况,朋友还要编写

朋友将用babelify转换来使用browserify和watchify来打包朋友的客户端代码。对于朋友的服务器端代码,朋友将直接使用babel-cli。

假设服务端返回以下的数据格式:

,朋友将都看以下响应:

本文来源: 掘金 如需转载请联系原作者

可能性重新启动服务器并打开相同的

最后有二个 还要优化的地方,却说我当可能性取到users时,还要阻止fetch

第两种最好的办法 ,还要朋友在两端做好具体情况管理。第二种最好的办法 还要朋友在服务端使用你这种 额外的库或工具,来确保同一套代码能在服务端和客户端做相同的事情,我被委托人比较推荐使用你这种 最好的办法 。

concurrently库帮助并行运行多个程序,这正是朋友在监控更改时还要的。

服务器端渲染,也叫代码同构,也却说我同一份代码既能在客户端渲染,又能在服务端渲染。

还记得朋友在客户端做的以下事情吗?

今天朋友将构建有二个 使用Redux的简单的React程序,实现服务端渲染(SSR)。该示例包括异步数据抓取,这使得任务变得更有趣。

你都看,朋友使用componentWillMount来发送fetchUsers请求,componentDidMount为你这种 非要用呢? 主要原应着是componentDidMount在服务端渲染过程中未必会执行。

有了你这种 文件,朋友可不还可以 运行npm run start并访问http://localhost:60 0。朋友都看数据获取成功,并成功的显示了。

reducer避免过程如下:

朋友在package.json中间加入以下有二个 命令脚本:

当然,现在并这么刚开始,客户端JavaScript谁能谁能告诉我服务器上位于了你这种 ,也谁能谁能告诉我朋友可能性对API进行了请求。朋友还要通过传递Store的具体情况来通知浏览器,以便它可不还可以 接收它。

注意typeof window !== 'undefined',朋友还要那我 做,可能性这段代码也会在服务端执行,这却说我为你这种 说在做服务端渲染还要非常小心,尤其是全局使用的浏览器api的很久。

你这种 将你这种 字符串加入到Express的响应中间,却说我服务端代码为:

这却说我有二个 简单的案例,实际开发场景往往比你这种 复杂化的多,还要考虑的具体情况也会非常多,朋友的服务端渲染是为什么么么在做的?

// App.jsx
import React from 'react';
import { connect } from 'react-redux';

import { getUsers } from './redux/selectors';
import { usersFetched } from './redux/actions';

const ENDPOINT = 'http://localhost:60

0/users_fake_data.json';

class App extends React.Component {
  componentWillMount() {
    fetchUsers();
  }
  render() {
    const { users } = this.props;

    return (
      <div>
        {
          users && users.length > 0 && users.map(
            // ... render the user here
          )
        }
      </div>
    );
  }
}

const ConnectedApp = connect(
  state => ({
    users: getUsers(state)
  }),
  dispatch => ({
    fetchUsers: async () => dispatch(
      usersFetched(await (await fetch(ENDPOINT)).json())
    )
  })
)(App);

export default ConnectedApp;

服务端几乎相同:

1、朋友明确知道请求的页面还要你这种 样的数据。朋友获取数据并使用该数据创建Redux存储。你这种 朋友通过提供已完成的Store来呈现页面,理论上朋友可不还可以 做到。

朋友使用了相同的组件<App />和 store,不同之位于于它返回的是有二个 字符串,而详细很久虚拟DOM。

朋友通过有二个 组件将数据渲染出来。在你这种 组件的componentWillMount生命周期最好的办法 中,朋友将触发数据获取,一旦请求成功,朋友将发送有二个 类型为user_fetch的操作。该操作将由有二个 reducer避免,朋友将在Redux存储中获得更新。具体情况的改变将触发朋友的组件重新呈现指定的数据。

2、朋友详细依赖于运行在客户端上的代码,计算出最终的结果。

import ReactDOM from 'react-dom';

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

朋友使用Storesubscribe最好的办法 来监听具体情况。当具体情况位于变化——是是否是有任何用户数据被获取。可能性users位于,朋友将unsubscribe(),那我 朋友就无需让相同的代码运行两次,你这种 朋友使用相同的存储实例转换为string。最后,朋友将标记输出到浏览器。

最后有二个 有用的命令,用于运行朋友的http服务器:

原文作者:感叹句

为了能埋点

fetchUsers是有二个 异步函数,它通过Fetch API请求数据。当数据返回时,会埋点users_fetch动作,从而通过reducer重新计算具体情况,而朋友的<App />可能性连接到Redux从而被重新渲染。

在刚开始编写应用很久,还要朋友先把环境编译/打包环境配置好,可能性朋友采用的是es6语法编写代码。朋友还要将代码编译成es5代码在浏览器或node环境中执行。