Saturday, 10 June 2017

Server rendering react-router v4 passthrough

In react-router v3 we could know when server side rendering had not matched against the current url. This allowed me to pass the request to my express.static middleware instead of sending the rendered App.

In react-router v4, we must use

    const htmlData = renderToString(
        <StaticRouter
            location={req.url}
            context={context}
        >
            <App/>
        </StaticRouter>
    );

in order to render on the server side. However, it automatically redirects everything to /. Why does this behavior even exist? Couldn't we just have an error like we expect insted of it silently failing?

How could I know that nothing matched so that I can call next() and have the other express's routes do the job?

Here is the whole function which I'd like to use:

app.get('*', (req, res, next) => {
    const context = {};
    const htmlData = renderToString(
        <StaticRouter
            location={req.url}
            context={context}
        >
            <App/>
        </StaticRouter>
    );

    console.log(JSON.stringify(context, null, 4)); // empty object
    if (context.url) { // <------------------------ Doesn't work (taken from example and thought it would contain the unmatched url)
        winston.info(`Passing ${req.url} along`);
        next(); // <--------------- Never called even if no route matches.
    } else {
        res.send(pageContent.replace('<div id="main"></div>',
            `<div id="main">${htmlData}</div>`));
    }
});

I tried doing stuff based on this but the // somewhere else is so precise, I couldn't understand it at all.

Here is my last attempt in case it is of any help. This is the Router.jsx file where I plan to define all my Routes.

import React from 'react';
import PropTypes from 'prop-types';
import {
    BrowserRouter,
    Route,
} from 'react-router-dom';
import App from './components/App.jsx';

export const Status = ({ code, children }) => (
    <Route render={({ staticContext }) => {
        if (staticContext) {
            staticContext.status = code;
        }
        return children;
    }}/>
);

Status.propTypes = {
    code     : PropTypes.number.isRequired,
    children : PropTypes.node.isRequired,
};

export const NotFound = () => (
    <Status code={404}>
        <div>
            <h1>Sorry, can’t find that.</h1>
        </div>
    </Status>
);

class Router extends React.Component {
    render() {
        return (
            <BrowserRouter>
                <div>
                    <Route exact path="/" component={App}/>
                    <Route component={NotFound}/>
                </div>
            </BrowserRouter>
        );
    }
}

export default Router;



via Ninetainedo

No comments:

Post a Comment