如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起

Jas*_*rer 6 reactjs react-router isomorphic-javascript redux

我希望我的基于React的SPA能够在服务器端呈现(这些日子不是这样).因此,我想将React与react-router,redux和一些构建层结合起来,就像isomorphic starterkit一样.

hapi通用redux连接在一起,但我正在努力如何组织我的流程.我的数据来自REST API的多个端点.不同的组件具有不同的数据需求,应该及时在客户端上加载数据.在服务器上,必须获取特定路由(组件集)的所有数据,并将必要的组件呈现给字符串.

在我的第一种方法中,我使用redux的中间件来创建异步操作,这些操作加载数据,返回一个promise,并SOME_DATA_ARRIVED在promise解析时触发一个动作.Reducers然后更新我的商店,组件重新渲染,一切都很好.原则上,这是有效的.但后来我意识到,在路由发挥作用的那一刻,流程变得尴尬.

列出许多数据记录的某个组件具有多个用于过滤记录的链接.每个过滤的数据集都应该通过它自己的URL来获取/filter-by/:filter.所以我使用不同的<Link to={...}>组件来更改点击的URL并触发路由器.路由器应根据当前URL表示的状态更新存储,这反过来导致相关组件的重新呈现.

这不容易实现.我componentWillUpdate首先尝试触发一个动作,异步加载我的数据,填充存储并为我的组件引起另一个重新渲染周期.但这不适用于服务器,因为只支持3种生命周期方法.

所以我正在寻找正确的方法来组织这个.用户与应用程序的交互(从用户角度更改应用程序状态)应更新URL.IMO这应该使路由器以某种方式加载必要的数据,更新商店,并开始对帐过程.

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

这种方法也应该在服务器上工作,因为从请求的URL开始,应该能够确定要加载的数据,生成initial state并将该状态传递给storeredux 的生成.但我找不到妥善做到这一点的方法.所以对我来说,出现以下问题:

  1. 我的方法是错误的,因为有一些我不理解/不知道的东西?
  2. 在redux中保持从REST API加载数据是正确的store吗?
  3. 拥有保留state在redux中的组件store以及其他state由自己管理的组件是不是有点尴尬?
  4. 这个想法是interaction -> URL change -> data fetching -> store update -> re-render完全错的吗?

我愿意接受各种建议.

Dav*_*ger 4

我今天确实设置了完全相同的东西。我们已经拥有的是一个react-router 和redux。我们模块化了一些模块,将东西注入其中 \xe2\x80\x93 和 viola \xe2\x80\x93\xc2\xa0it 工作。我使用https://github.com/erikras/react-redux-universal-hot-example作为参考。

\n\n

零件:

\n\n

1. 路由器.js

\n\n

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

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

2.store.js

\n\n

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

\n\n

3.服务端渲染

\n\n

获取数据,使用该数据设置初始状态 ( ...data)。createRouter=router.js从上面。res.render是使用以下内容快速渲染玉石模板

\n\n
script.\n    window.csvistate.__initialstate__=!{initialState ? JSON.stringify(initialState) : \'null\'};\n...\n#react-start\n    != html\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n
var initialState = { ...data };\nvar store = createStore(reducer, initialState);\ncreateRouter(req.url, null, store).then(function (component) {\n    var html = React.renderToString(component);\n    res.render(\'community/neighbourhood\', { html: html, initialState: initialState });\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

4. 适配客户端

\n\n

然后,您的客户可以做基本相同的事情。location可能HistoryLocation来自 React-Router

\n\n
const initialState = window.csvistate.__initialstate__;\nconst store = require(\'./store\')(initialState);\n\nrouter(location, null, store).then(component => {\n    React.render(component, document.getElementsByClassName(\'jsx-community-bulletinboard\')[0]);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

回答您的问题:

\n\n
    \n
  1. 你的做法似乎是正确的。我们也这样做。甚至可以将 URL 作为状态的一部分。
  2. \n
  3. Redux 存储中的所有状态都是一件好事。这样你就拥有了单一的事实来源。
  4. \n
  5. 我们现在仍在研究什么应该放在哪里。componentDidMount目前我们请求服务器上的数据应该已经在那里了。
  6. \n
\n