使用服务器道具实现路由器服务器渲染

时间:2016-05-16 19:12:49

标签: javascript reactjs react-router

Here's an example from the docs.

import { renderToString } from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import routes from './routes'

serve((req, res) => {
  // Note that req.url here should be the full URL path from
  // the original request, including the query string.
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
      // You can also check renderProps.components or renderProps.routes for
      // your "not found" component or route respectively, and send a 404 as
      // below, if you're using a catch-all route.
      res.status(200).send(renderToString(<RouterContext {...renderProps} />))
    } else {
      res.status(404).send('Not found')
    }
  })
})

我有一个这样的对象:

let reactServerProps = {
  'gaKey': process.env.GA_KEY,
  'query': req.query,
}

我试图将此对象传递到此处的反应路由器

res.status(200).send(renderToString(<RouterContext {...renderProps} {...reactServerProps} />))

我似乎无法从我的组件中提供对变量的访问。

2 个答案:

答案 0 :(得分:3)

问题是<ReactContext />只将一些react-router预定义道具传递给它构建的组件树,而不是普通组件中你可能期望的自定义​​道具。

这个问题有一些解决方法,但它们都不是特别漂亮。我认为最广泛使用的是用<ReactContext />包装一个组件,其唯一目的是利用React的上下文功能&amp;将上下文数据传递给它的子节点而不是道具。

所以:

import React from 'react';

export default class DataWrapper extends React.Component {

getChildContext () {

    return {
        data: this.props.data
    };

}

render () {

    return this.props.children;
}
}

然后在您的快递服务器中:

// Grab the data from wherever you need then pass it to your <DataWrapper /> as a prop 
// which in turn will pass it down to all it's children through context
res.status(200).send(renderToString(<DataWrapper data={data}><RouterContext {...renderProps} /></DataWrapper>))

然后您应该能够访问子组件中的数据:

export default class SomeChildComponent extends React.Component {

constructor (props, context) {

    super(props, context);
    this.state = {
        gaKey: context.data.gaKey,
        query: context.data.query
    };
}

};

我知道以前可以使用createElement方法来设置一些自定义道具,并以类似的方式将它们传递到您的子路线,但我并不认为&#39 ; s在较新版本的react-router中仍然有效。请参阅:https://github.com/reactjs/react-router/issues/1369

更新:仍然可以使用中间件将其他值传递到路径组件中。通过:https://github.com/reactjs/react-router/issues/3183

你应该能够在上下文中使用道具:

function createElementFn(serverProps) {
  return function(Component, props) {
    return <Component {...serverProps} {...props} />
  }
} 

然后在createElement中添加<RouterContext />,将其传递给serverProps:

res.status(200).send(renderToString(<RouterContext {...renderProps} createElement={createElementFn(serverProps)} />)) 

使用简单的this.props.gaKey&amp;可以在您的任何子组件中访问它们this.props.query

答案 1 :(得分:-1)

一个更简单的解决方案是在props.routes中放置您想要的任何数据,它将被传递到您可以直接通过

访问它的组件

props.routes.[whatever you passed in]

所以在服务功能中你可以做到

props.routes.reactServerProps = {
'gaKey': process.env.GA_KEY,
'query': req.query
}

在您的组件中,您可以使用props.routes.reactServerProps访问它。

查看Ryan Florence的最后评论。 https://github.com/ReactTraining/react-router/issues/1017

他忘记了(s)。不适用于路线。