如何使用 React + Redux 水合服务器端参数 [英] How to hydrate server-side parameters with React + Redux

查看:80
本文介绍了如何使用 React + Redux 水合服务器端参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 Redux 和 React Router 的通用 React 应用程序.我的一些路由包含参数,这些参数会在客户端触发 AJAX 请求以将数据混合以供显示.在服务器上,这些请求可以同步完成,并在第一个请求时呈现.

I have a universal React app that is using Redux and React Router. Some of my routes include parameters that, on the client, will trigger an AJAX request to hydrate the data for display. On the server, these requests could be fulfilled synchronously, and rendered on the first request.

我遇到的问题是:当在路由组件上调用任何生命周期方法(例如 componentWillMount)时,分派将反映在第一次渲染.

The problem I'm running into is this: By the time any lifecycle method (e.g. componentWillMount) is called on a routed component, it's too late to dispatch a Redux action that will be reflected in the first render.

这是我的服务器端渲染代码的简化视图:

Here is a simplified view of my server-side rendering code:

routes.js

export default getRoutes (store) {
  return (
    <Route path='/' component={App}>
      <Route path='foo' component={FooLayout}>
        <Route path='view/:id' component={FooViewContainer} />
      </Route>
    </Route>
  )
}

server.js

let store = configureStore()
let routes = getRoutes()
let history = createMemoryHistory(req.path)
let location = req.originalUrl
match({ history, routes, location }, (err, redirectLocation, renderProps) => {
  if (redirectLocation) {
    // redirect
  } else if (err) {
    // 500
  } else if (!renderProps) {
    // 404
  } else {
    let bodyMarkup = ReactDOMServer.renderToString(
      <Provider store={store}>
        <RouterContext {...renderProps} />
      </Provider>)
    res.status(200).send('<!DOCTYPE html>' +
      ReactDOMServer.renderToStaticMarkup(<Html body={bodyMarkup} />))
  }
})

FooViewContainer 组件在服务器上构建时,它的第一次渲染的 props 已经被修复了.我分派到商店的任何操作都不会反映在对 render() 的第一次调用中,这意味着它们不会反映在页面请求中传递的内容中.

When the FooViewContainer component is constructed on the server, its props for the first render will already be fixed. Any action I dispatch to the store will not be reflected in the first call to render(), which means that they won't be reflected in what's delivered on the page request.

React Router 传递的 id 参数本身对于第一次渲染没有用.我需要将该值同步地合成一个合适的对象.我应该把这个补水放在哪里?

The id parameter that React Router passes along isn't, by itself, useful for that first render. I need to synchronously hydrate that value into a proper object. Where should I put this hydration?

一种解决方案是将它内联放在 render() 方法中,例如在服务器上调用它的地方.这对我来说显然是不正确的,因为 1)它在语义上没有意义,2)它收集的任何数据都不会正确发送到商店.

One solution would be to put it, inline, inside the render() method, for instances where it's invoked on the server. This seems obviously incorrect to me because 1) it semantically makes no sense, and 2) whatever data it collects wouldn't be properly dispatched to the store.

我看到的另一个解决方案是向路由器链中的每个容器组件添加一个静态 fetchData 方法.例如像这样:

Another solution which I have seen is to add a static fetchData method to each of the container components in the Router chain. e.g. something like this:

FooViewContainer.js

class FooViewContainer extends React.Component {

  static fetchData (query, params, store, history) {
    store.dispatch(hydrateFoo(loadFooByIdSync(params.id)))
  }

  ...

}

server.js

let { query, params } = renderProps
renderProps.components.forEach(comp => 
  if (comp.WrappedComponent && comp.WrappedComponent.fetchData) {
    comp.WrappedComponent.fetchData(query, params, store, history)
  }
})

我觉得必须有比这更好的方法.它不仅看起来相当不雅(.WrappedComponent 是一个可靠的接口吗?),而且它也不适用于高阶组件.如果任何路由组件类被 connect() 以外的任何东西包裹,这将停止工作.

I feel there must be better approach than this. Not only does it seem to be fairly inelegant (is .WrappedComponent a dependable interface?), but it also doesn't work with higher-order components. If any of the routed component classes is wrapped by anything other than connect() this will stop working.

我在这里遗漏了什么?

推荐答案

我最近写了一篇关于这个需求的文章,但它确实需要使用 redux-saga.从 redux-thunk 的角度来看,它确实可以使用这种静态的 fetchData/need 模式.

I recently wrote an article around this requirement, but it does require the use of redux-sagas. It does pickup from the point of view of redux-thunks and using this static fetchData/need pattern.

https://medium.com/@navgarcha7891/react-server-side-rendering-with-simple-redux-store-hydration-9f77ab66900a

我认为这个传奇方法更清晰、更容易推理,但这可能只是我的意见:)

I think this saga approach is far more cleaner and simpler to reason about but that might just be my opinion :)

这篇关于如何使用 React + Redux 水合服务器端参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆