基于React+Redux的SSR实现

  • 时间:
  • 浏览:1

因此 重新启动服务器并打开相同的

不使用node ./build/server/server.js而使用Nodemon的意味着是,它时要监控人们人们代码中的任何更改,并自动重新启动服务器。这或多或少在开发过程会非常有用。

因此 将这些字符串加入到Express的响应后面 ,什么都有有服务端代码为:

第有一种方式,时要人们人们在两端做好状态管理。第二种方式时要人们人们在服务端使用或多或少额外的库或工具,来确保同一套代码能在服务端和客户端做相同的事情,我我各自 所有比较推荐使用这些方式。

注意typeof window !== 'undefined',人们人们时要原先 做,因此 这段代码也会在服务端执行,这后来为那些说在做服务端渲染时要非常小心,尤其是全局使用的浏览器api的后来。

,人们人们将看多以下响应:

有了后面 的代码,人们人们的组件因此 时要成功地在服务器端渲染。通过开发者工具,人们人们时要看多发送到浏览器的内容:

这后来原先简单的案例,实际开发场景往往比这些复杂化的多,时要考虑的状态也会非常多,人们人们的服务端渲染是为社 做的?

1、人们人们明确知道请求的页面时要那些样的数据。人们人们获取数据并使用该数据创建Redux存储。因此 人们人们通过提供已完成的Store来呈现页面,理论上人们人们时要做到。

在这里时要提的原先重点是,一旦人们人们想实现服务端渲染,原先 们就时要改变后来的纯客户端编程模式。

store.subscribe方式返回原先函数,调用这些函数就时要解除监听

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

在开使编写应用后来,时要人们人们先把环境编译/打包环境配置好,因此 人们人们采用的是es6语法编写代码。人们人们时要将代码编译成es5代码在浏览器或node环境中执行。

实现的最关键一步后来创建

人们人们时要保证代码能在服务端正常的运行。这些,访问Window对象,Node不提供Window对象的访问。

为了能采集

人们人们在package.json后面 加入以下原先命令脚本:

最后原先有用的命令,用于运行人们人们的http服务器:

当然,现在并那末 开使,客户端JavaScript问你服务器上居于了那些,也问你人们人们因此 对API进行了请求。人们人们时要通过传递Store的状态来通知浏览器,以便它都都还都可以接收它。

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

<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>

总结下来有以下几点:

人们人们的页面中虽然有或多或少内容,但它后来<div data-reactroot=""></div>。这未必意味着分析守护tcp连接出错了。这绝对是正确的。React虽然呈现了人们人们的页面,但它只呈现静态内容。在人们人们的组件中,人们人们在获取数据后来那些都那末 ,数据的获取是原先异步过程,在服务器上呈现时,人们人们时要考虑到这或多或少。这后来人们人们的任务变得棘手的地方。这时要归结为人们人们的应用守护tcp连接在做那些。在本例中,客户端代码依赖于原先特定的请求,但因此 使用redux-saga库,则因此 是多个请求,因此 因此 是原先完整篇 的root saga。我意识到外理这些现象的有一种方式:

原文作者:感叹句

import ReactDOM from 'react-dom';

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

人们人们通过原先组件将数据渲染出来。在这些组件的componentWillMount生命周期方式中,人们人们将触发数据获取,一旦请求成功,人们人们将发送原先类型为user_fetch的操作。该操作将由原先reducer外理,人们人们将在Redux存储中获得更新。状态的改变将触发人们人们的组件重新呈现指定的数据。

代码型态如下:

服务器端呈现是原先有趣得话题。它有什么都有有优势,并改善了整体用户体验。它时要提升你的单页应用守护tcp连接的SEO。但这些切未必简单。在大多数状态下,时要额外的工具和精心选折 的api。

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

人们人们使用了相同的组件<App />和 store,不同之居于于它返回的是原先字符串,而时要虚拟DOM。

你看多,人们人们使用componentWillMount来发送fetchUsers请求,componentDidMount为那些还都可以 用呢? 主要意味着是componentDidMount在服务端渲染过程中未必会执行。

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

concurrently库帮助并行运行多个守护tcp连接,这正是人们人们在监控更改时时要的。

人们人们使用Storesubscribe方式来监听状态。当状态居于变化——是是不是有任何用户数据被获取。因此 users居于,人们人们将unsubscribe(),原先 人们人们就不想让相同的代码运行两次,因此 人们人们使用相同的存储实例转换为string。最后,人们人们将标记输出到浏览器。

人们人们使用客户端API接收异步数据,一旦Store获取到异步数据,人们人们将触发ReactDOMServer.renderToString。它会提供给人们人们你会的标记。人们人们的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:4000/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;

2、人们人们完整篇 依赖于运行在客户端上的代码,计算出最终的结果。

这些,人们人们使用了Fetch API向后端发出异步请求,而服务端默认是不支持的。人们人们时要做的后来在 server.js中将Fetch导入:

fetchUsers是原先异步函数,它通过Fetch API请求数据。当数据返回时,会采集users_fetch动作,从而通过reducer重新计算状态,而人们人们的<App />因此 连接到Redux从而被重新渲染。

:

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

请求去改变应用状态,人们人们时要编写

为那些直接返回的是工厂函数而时要createStore(reducer)?这是因此 人们人们在服务器端渲染时,人们人们时要原先全新的Store实例来外理每个请求。

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

最后原先时要优化的地方,后来当因此 取到users时,时要阻止fetch

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

有了这些文件,人们人们时要运行npm run start并访问http://localhost:4000。人们人们看多数据获取成功,并成功的显示了。

reducer外理过程如下:

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

今天人们人们将构建原先使用Redux的简单的React应用守护tcp连接,实现服务端渲染(SSR)。该示例包括异步数据抓取,这使得任务变得更有趣。

服务端几乎相同: