Reputation: 59345
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')
}
})
})
I have an object like this:
let reactServerProps = {
'gaKey': process.env.GA_KEY,
'query': req.query,
}
I'm trying to pass this object into react router here
res.status(200).send(renderToString(<RouterContext {...renderProps} {...reactServerProps} />))
And I can't seem to provide access to the variables from within my components.
Upvotes: 3
Views: 722
Reputation: 2040
A much simpler solution is to put whatever data you want in props.routes
and it will be passed to your component where you can access it directly through
props.routes.[whatever you passed in]
So in the serve function you can do
props.routes.reactServerProps = {
'gaKey': process.env.GA_KEY,
'query': req.query
}
and in your component you can access it with props.routes.reactServerProps
.
See the very last comment by Ryan Florence. https://github.com/ReactTraining/react-router/issues/1017
He forgot the (s). Won't work with route.
Upvotes: -1
Reputation: 2605
The issue is that <ReactContext />
only passes some react-router pre-defined props down to the component tree that it builds rather than the custom props you might expect in a normal component.
There are a few workarounds to this issue, though none of them are particularly pretty. The most widely used I think I've seen is to wrap <ReactContext />
with a component whose sole purpose is to make use of React's context feature & pass contextual data down to its children rather than props.
So:
import React from 'react';
export default class DataWrapper extends React.Component {
getChildContext () {
return {
data: this.props.data
};
}
render () {
return this.props.children;
}
}
Then in your express server:
// 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>))
And you should then be able to access that data in your child components:
export default class SomeChildComponent extends React.Component {
constructor (props, context) {
super(props, context);
this.state = {
gaKey: context.data.gaKey,
query: context.data.query
};
}
};
I know it used to be possible to make use of the createElement
method to set some custom props and pass them through to your child routes in a similar fashion, but I'm not positive that's still valid in newer versions of react-router. See: https://github.com/reactjs/react-router/issues/1369
UPDATE: It is still possible to use middleware to pass additional values into route components. via: https://github.com/reactjs/react-router/issues/3183
And you should be able to make use of props over context:
function createElementFn(serverProps) {
return function(Component, props) {
return <Component {...serverProps} {...props} />
}
}
Then add createElement
in your <RouterContext />
like so, passing it your serverProps:
res.status(200).send(renderToString(<RouterContext {...renderProps} createElement={createElementFn(serverProps)} />))
And access them in any of your child components with a simple this.props.gaKey
& this.props.query
Upvotes: 3