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 Route
s.
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;
(I know this doesn't make any sense at all since StaticRouter
directly uses App
without caring about Router.jsx
but I have no Route
at all inside App
so I don't really understand how to do things, I guess.
You should put NotFoundPage component route logic inside your App.jsx file, not Route.jsx which you are not using at all.
<Switch>
<Route exact path="/" component={AppRootComponent}/>
<Route component={NotFound}/>
</Switch>
In addition to this, this tutorial code is a great reference for server-side rendering using react router v4.
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