2015-08-28 37 views
6

我希望我的基于React的SPA能够在服务器端呈现(现在不是这些日子)​​。因此,我想将React与react-router,redux和一些构建层(如isomorphic starterkit)结合使用。如何在逻辑上组合react-router和redux以进行客户端和服务器端渲染

hapi universal redux加入到一起,但我正在努力如何组织我的流量。我的数据来自REST API的多个端点。不同的组件有不同的数据需求,应该及时在客户端上加载数据。而是在服务器上,必须获取特定路由(组件集合)的所有数据,并将必要组件呈现为字符串。

在我的第一个方法中,我使用了redux的中间件来创建异步操作,它加载数据,返回一个承诺,并在承诺解决时触发一个SOME_DATA_ARRIVED操作。 Reducers然后更新我的商店,组件重新渲染,都很好。原则上,这是有效的。但后来我意识到,在路由开始的时候,流量变得尴尬。

某些列出大量数据记录的组件具有多个链接来过滤记录。每个过滤的数据集应该可以通过它自己的URL(如/filter-by/:filter)获得。所以我使用不同的<Link to={...}>组件在点击时更改URL并触发路由器。路由器应根据当前URL所代表的状态更新商店,从而导致相关组件的重新呈现。

这并不容易实现。我首先试着componentWillUpdate来触发一个动作,它异步加载我的数据,填充存储并为我的组件导致另一个重新呈现周期。但是这不适用于服务器,因为只支持3种生命周期方法。

所以我正在寻找正确的方式来组织这一点。从用户角度更改应用程序状态的用户与应用程序的交互应更新URL。海事组织这应该使路由器以某种方式加载必要的数据,更新商店,并启动对帐过程。

所以interaction -> URL change -> data fetching -> store update -> re-render

这种方法也应该在服务器上工作,因为根据请求的URL,应该能够确定要加载的数据,生成initial state并将该状态传递到store generation的redux。但我没有找到正确的方法。所以对我来说,出现以下问题:

  1. 我的方法错了吗,因为有些东西我不明白/知道吗?
  2. 将REST API的数据加载到redux的store中是否正确?
  3. 是不是有一个尴尬的组件,其中state在redux store和其他人管理他们state自己?
  4. 想法有interaction -> URL change -> data fetching -> store update -> re-render简直是错的吗?

我对每一种建议都是开放的。

回答

3

今天我确实设置了完全相同的东西。我们已经拥有的是反应路由器和redux。我们模块化了一些模块,将注入的东西 - 中提琴 - 它的工作原理。我用https://github.com/erikras/react-redux-universal-hot-example作为参考。

的部分:

1. router.js

我们返回function (location, history, store)使用承诺,设置路由器。 routes是包含所有组件的react-router的路由定义。

module.exports = function (location, history, store) { 
    return new Bluebird((resolve, reject) => { 
     Router.run(routes, location, (Handler, state) => { 
      const HandlerConnected = connect(_.identity)(Handler); 
      const component = (
       <Provider store={store}> 
        {() => <HandlerConnected />} 
       </Provider> 
      ); 
      resolve(component); 
     }).catch(console.error.bind(console)); 
    }); 
}; 

2. store.js

你只是通过初始状态createStore(reducer, initialState)。您只需在服务器和客户端上执行此操作。对于客户端,您应该通过脚本标签使状态可用(即,window.__initialstate__)。 有关更多信息,请参阅http://rackt.github.io/redux/docs/recipes/ServerRendering.html。服务器

3.渲染让您的数据,建立初始状态与数据(...data)。 createRouter = router.js从上面。 res.render是快递渲染玉模板使用下列

script. 
    window.csvistate.__initialstate__=!{initialState ? JSON.stringify(initialState) : 'null'}; 
... 
#react-start 
    != html 

var initialState = { ...data }; 
var store = createStore(reducer, initialState); 
createRouter(req.url, null, store).then(function (component) { 
    var html = React.renderToString(component); 
    res.render('community/neighbourhood', { html: html, initialState: initialState }); 
}); 

4.适应客户

你的客户端就可以基本上做同样的事情。 location可能是HistoryLocation从阵营,路由器

const initialState = window.csvistate.__initialstate__; 
const store = require('./store')(initialState); 

router(location, null, store).then(component => { 
    React.render(component, document.getElementsByClassName('jsx-community-bulletinboard')[0]); 
}); 

回答您的问题:

  1. 你的做法似乎是正确的。我们也这样做。甚至可以将url包含为该州的一部分。
  2. redux商店内的所有状态都是好事。这样你就有了唯一的真理来源。
  3. 我们仍在研究现在应该去的地方。目前我们请求服务器上的数据componentDidMount,它应该已经在那里。
相关问题