使用服务器属性进行React Router服务器渲染

3

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,
}

我正在尝试在这里将此对象传递给React Router。
res.status(200).send(renderToString(<RouterContext {...renderProps} {...reactServerProps} />))

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

2个回答

3
问题在于<ReactContext />只向组件树传递一些预定义的react-router属性,而不是您在普通组件中期望的自定义属性。
虽然有一些解决方法,但它们都不是特别优雅。我认为最广泛使用的方法是将<ReactContext />包装在一个组件中,其唯一目的是利用React的上下文功能并将上下文数据传递给其子代,而不是通过props传递。
所以:
import React from 'react';

export default class DataWrapper extends React.Component {

getChildContext () {

    return {
        data: this.props.data
    };

}

render () {

    return this.props.children;
}
}

然后在您的Express服务器中:

// 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方法设置一些自定义属性,并以类似的方式将它们传递给子路由,但我不确定在新版本的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} />
  }
} 

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

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

您可以通过简单的 this.props.gaKey & this.props.query 在任何子组件中访问它们。


我已经使用props命名空间将所有组件连接起来,寻找变量。有没有办法将数据作为props传递? - ThomasReggi
你可以试试createElement方法,我在这里找到了一种实现方式:http://stackoverflow.com/questions/33978781。不过,我不确定这是否适用于react-router v1。我认为也有可能,尽管它看起来有点hacky,使用Object assign()方法直接将你的数据注入到renderProps中。例如)assign(renderProps.params, reactServerProps) - Brad Colthurst
@ThomasReggi 好消息,似乎将值作为props传递给所有子组件仍然是完全可行的,而不是使用context。已更新答案进行说明。 - Brad Colthurst
谢谢,我需要更深入地研究一下! - ThomasReggi
我遇到了一个问题。比如props.query会闪现一秒然后就消失了。这是怎么回事? - boozi

-1
一个更简单的解决方案是将您想要的任何数据放入props.routes中,它将传递到您的组件,您可以直接通过props.routes.[您传递的任何内容]访问它。
因此,在serve函数中,您可以执行以下操作:
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)。与 route 不兼容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接