【问题标题】:React + Flux and Server-side rendering? (Isomorphic React + Flux)React + Flux 和服务器端渲染? (同构反应 + 通量)
【发布时间】:2015-02-04 20:41:46
【问题描述】:

使用同构应用程序设置应用程序初始状态的一般做法是什么?如果没有 Flux,我会简单地使用类似的东西:

var props = { }; // initial state
var html = React.renderToString(MyComponent(props);

然后通过express-handlebars 渲染该标记并通过{{{reactMarkup}} 显示。

在客户端设置初始状态我会做这样的事情:

if (typeof window !== 'undefined') {
    var props = JSON.parse(document.getElementById('props').innerHTML);
    React.render(MyComponent(props), document.getElementById('reactMarkup'));
}

所以是的,基本上你在服务器和客户端设置了两次状态,但是 React 会比较差异,并且在大多数情况下,它不会通过重新渲染来影响性能。


当您在 Flux 架构中有操作和存储时,该原则将如何工作?在我的组件中,我可以这样做:

getInitialState: function() {
  return AppStore.getAppState();
}

但是现在我如何从服务器设置 AppStore 中的初始状态?如果我使用没有传递属性的React.renderToString,它将调用AppStore.getAppState(),因为我仍然不明白如何在服务器上的商店中设置状态?

2015 年 2 月 5 日更新

我仍在寻找不涉及使用第三方 Flux 实现(例如 Fluxible、Fluxxor、Reflux)的干净解决方案。

2016 年 8 月 19 日更新

使用Redux

【问题讨论】:

  • 嗨,您找到没有第三方助焊剂实现的解决方案了吗?
  • 你不能只添加 AppStore.setAppState({...}) 方法在服务器上使用吗? Node.js 是单线程和 renderToString 同步方法,它应该可以正常工作。
  • 只需在组件中添加一个静态 getStore 并在 Store 中添加一个加载方法并在渲染之前加载数据。您可能还想向商店添加一个 createStore,以便在每次请求中加载新数据之前调用它。

标签: javascript express reactjs flux isomorphic-javascript


【解决方案1】:

看看dispatchr 和雅虎的相关库。

大多数 Flux 实现在 node.js 中不起作用,因为它们使用单​​例存储、调度程序和操作,并且没有“我们完成”的概念,这需要知道何时呈现到 html 并响应请求。

雅虎的 fetchr 和 routr 等库通过使用非常纯粹的依赖注入形式(没有解析参数名称或类似的函数)来绕过节点的这种限制。

相反,您可以在 services/todo.js 中定义这样的 api 函数:

create: function (req, resource, params, body, config, callback) {

actions/createTodo.js 中的类似操作:

module.exports = function (context, payload, done) {
    var todoStore = context.getStore(TodoStore);
...
context.dispatch('CREATE_TODO_START', newTodo);
...
context.service.create('todo', newTodo, {}, function (err, todo) {

最后一行间接调用了 services/todo.js 中的 create 函数。在这种情况下,间接意味着:

  • 在服务器上:
    • 当您在服务器上时,fetchr 会填充额外的参数
    • 然后它会调用您的回调
  • 在客户端:
    • fetchr 客户端发出一个 http 请求
    • 服务器上的 fetchr 拦截它
    • 它使用正确的参数调用服务函数
    • 它将响应发送回客户端 fetchr
    • 客户端提取器处理调用您的回调

这只是冰山一角。这是一组非常复杂的模块,它们协同工作以解决棘手的问题并提供可用的 api。在现实世界的用例中,同构本质上是复杂的。这就是为什么许多 Flux 实现不支持服务器端渲染的原因。

您可能还想考虑不使用助焊剂。它对所有应用程序都没有意义,而且经常会妨碍您。大多数情况下,如果有的话,您只需要它用于应用程序的几个部分。编程没有灵丹妙药!

【讨论】:

  • 感谢您的出色回答。我看过 Yahoo 的 todo 示例,但不喜欢它引入了诸如fluxible 和 fetchr 之类的新东西。但是正如您所说,服务器上的 Flux 本质上是复杂的,因此这可能是目前唯一可行的解​​决方案。你可能是对的,因为我没有构建一个完整的单页应用程序——只是 React 中的一小部分,也许 Flux 不适合这里。
  • 任何时候都可以提前知道组件需要什么数据,服务端代码很简单。您获取数据,将其作为 props 传递给组件,并将其作为 json 放入
【解决方案2】:

FakeRainBrigand 是正确的,服务器端 Flux 的最大问题是单例。 Flummox 通过不使用单例解决了这个问题,使您能够将整个 Flux 设置封装到一个可重用的单个类中。然后,您只需在每个请求上创建一个新实例。结合 React Router 等路由解决方案,您可以制作完全同构的应用程序。

即使您不想使用 Flummox,源代码也很容易理解,您可以将其用作自己的指南:

https://github.com/acdlite/flummox

【讨论】:

    【解决方案3】:

    如果您愿意使用alt.js,您可以使用alt.bootstrapalt.flush (docs) 实现它

    我正在使用带有 react 服务器端渲染的 node js 和 alt.js 作为我的通量实现。

    看起来是这样的:

    var data = {}; // Get the data whatever you want and return it bootstrap ready.
    
    // Reminder - renderToString is synchronised
    var app = React.renderToString(
         AppFactory(data)
    );
    
    // In this point the react rendering was finished so we can flush the data and reset the stores
    
    alt.flush();
    

    在我的 app.jsx 中

    /**
     *
     */
    componentWillMount: function () {
    
        // This beauty here is that componentWillMount is run on the server and the client so this is all we need to do. No need for other third-party isomorphic frameworks
    
        alt.bootstrap(
            JSON.stringify(this.props, null, 3)
        );
    
    }
    

    【讨论】:

      【解决方案4】:

      问题是当你搜索 “Flux 服务器渲染” 时,你会立即碰到这个问题,并且没有提到由 React.js 社区提出的Reduxrackt。你可以在 Redux 的 documentation 找到很好的描述为什么服务器渲染很重要,为什么我们需要在 HTML 中将初始状态发送到客户端(这是 Flux 变得不够用的地方)以及如何这样做。

      【讨论】:

        猜你喜欢
        • 2017-01-08
        • 2017-01-14
        • 2017-12-29
        • 2016-10-07
        • 2016-10-12
        • 1970-01-01
        • 1970-01-01
        • 2016-03-26
        • 2015-05-09
        相关资源
        最近更新 更多