Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs router match callback parameters are always undefined

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

}
like image 449
Raphael Parent Avatar asked Nov 04 '15 17:11

Raphael Parent


People also ask

Why is match undefined react Router?

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.

How do you parameter react to Router?

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.

Is react Router deprecated?

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 .

Does react Support route parameters?

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.


4 Answers

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 ...
like image 182
Jan Avatar answered Nov 10 '22 01:11

Jan


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...];.

like image 44
delovely86 Avatar answered Nov 09 '22 23:11

delovely86


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}
like image 30
Kaman Wu Avatar answered Nov 10 '22 00:11

Kaman Wu


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

like image 38
user3763020 Avatar answered Nov 09 '22 23:11

user3763020