I use the match
method for my server side rendering and the parameters in the callback are always undefined. Probably got something wrong but it's been a complete day and I can't get my head around it.
Here's my server side rendering.
// Create location from the history module.
let location = createLocation(req.url);
match({Routes, location}, (error, redirectLocation, renderProps) => {
// TODO : Verify why this is always undefined
console.log('ERROR :: ', error)
console.log('REDIRECT LOCATION :: ', redirectLocation)
console.log('RENDER PROPS :: ', renderProps)
if (redirectLocation) {
res.redirect(redirectLocation.pathname + redirectLocation.search)
}
// TODO : Verify why this is breaking
//else if (error || !renderProps) {
// return console.log('Error while starting server :: ', error)
//}
else {
Transmit.renderToString(RoutingContext, renderProps).then(({reactString, reactData}) => {
console.log('REACT STRING :: ', reactString);
console.log('REACT DATA :: ', reactData);
let output = (
`<!doctype html>
<html lang="en-us" style="min-height:100vh; width: 100%; background-color: #eee;">
<head>
<meta charset="utf-8">
<title>react-isomorphic-pandora-app</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:400,100,700">
</head>
<body>
<div id="react-root">${reactString}</div>
</body>
</html>`
);
var webserver = process.env.NODE_ENV === "production" ? "" : "//localhost:8080"
output = Transmit.injectIntoMarkup(output, reactData, [`${webserver}/dist/client.js`])
res.send(output)
}).catch((error) => {
res.send(error.stack).type("text/plain").code(500)
})
}
})
Here is my client side.
import React from "react";
import ReactDOM from "react-dom";
import {Router} from "react-router";
import Transmit from "react-transmit";
import routes from "../views/Routes";
import {createHistory} from "history";
let reactRoot = window.document.getElementById("react-root");
let history = createHistory();
let location = history.createLocation();
const routerOption = {
routes: routes,
history: history,
location: location
}
Transmit.render(Router, routerOption, reactRoot);
if (process.env.NODE_ENV !== "production") {
if (!reactRoot.firstChild || !reactRoot.firstChild.attributes ||
!reactRoot.firstChild.attributes["data-react-checksum"]) {
console.error("Server-side React render was discarded. Make sure that your initial render does not contain any client-side code.");
}
}
Here are my routes.
import React from "react"
import {Router, Route} from "react-router"
import MenuView from "./Menu"
import DefaultView from "./Default"
import AnotherView from "./Another"
export default (
<Router component={MenuView}>
<Route path="/" component={DefaultView} />
<Route path="/another-view" component={AnotherView} />
</Router>
);
Any help would be appreciated. Thanks :)
EDIT --------
Here's the code inside my MenuView component.
class MenuView extends React.Component {
constructor(){
super()
this.menuItems = [
{
type: MenuItem.Types.SUBHEADER,
text: 'Menu sub header'
},
{
route: '/',
text: 'Home'
},
{
route: '/another-view',
text: 'Another view'
}
]
}
childContextTypes = {
muiTheme: React.PropTypes.object
};
getChildContext() {
return {
muiTheme: ThemeManager.getMuiTheme(DefaultTheme)
}
}
_getSelectedIndex = () => {
let currentItem;
for (let i = this.menuItems.length - 1; i >= 0; i--) {
currentItem = this.menuItems[i];
if (currentItem.route && this.props.history.isActive(currentItem.route)) return i;
}
}
_onLeftNavChange = (e, key, payload) => {
this.props.history.pushState(null, payload.route);
}
render () {
var style = {
paddingTop: '92px'
}
return (
<div>
<LeftNav
ref="leftNav"
menuItems={this.menuItems}
onChange={this._onLeftNavChange}
selectedIndex={this._getSelectedIndex()}
style={style}/>
<section className="content">
{this.props.children}
</section>
</div>
)
}
}
react-router-dom v5 If using RRDv5 if the match prop is undefined this means that BookScreen isn't receiving the route props that are injected when a component is rendered on the Route component's component prop, or the render or children prop functions.
To get path params in React Router, we can use the useParams hook. We create the Child component that calls the useParams hook to return an object with the route params in the URL. And we render the value of the id param on the page. In App , we have 2 links that goes to routes with different id param values.
Thus, we found that a lot of the packages were deprecated and needed to be replaced ASAP. One of the biggest surprises for us was the deprecation of react-router-redux .
Using React Router, when you want to create a Route that uses a URL parameter, you do so by including a : in front of the value you pass to Route 's path prop. Finally, to access the value of the URL parameter from inside of the component that is rendered by React Router, you can use React Router's useParams Hook.
Due to Babel 5 vs. Babel 6 and exporting routes file it should look like this:
Babel 5:
Router.match({ routes:routes, location: req.url}, etc ...
Babel 6:
Router.match({ routes:routes.default, location: req.url}, etc ...
The problem is the exports default
in the routes file. It returns an object like { defaults: { // routes in here }
whereas on the client, it returns an object like { // routes in here }
. You need to export the file in a different manner like modules.exports = [...routes...];
.
I guess you use babel 6, NOT babel 5.
I had a similar problem. It's OK with babel 5, but NOT with babel 6.
After long debugging, I found that making the following change fixes the problem for me.
change:
match({Routes, location}
to:
match({Routes.default, location}
You got es6 destructuring assignment wrong. Destructuring assignment
match({Routes, location})
needs to be match({routes, location})
Or more safe way
match({routes:Routes, location:location})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With