1

I'm developing isomorphic app with react-router & express. I'm using react router in server side rendering. I want to have custom error pages, that will be sent upon either server-side error, rendering error or ofcourse- not found. But I'm having problems connecting the dots. Here are my routes:

<Route component={Index} path="/">
  <IndexRoute component={Home} />
  <Route component={Chart} path="chart" />
  <Route component={Login} path="login" />
  <Route component={Error} path="error" /> //path="*" takes care only for not found,
                                             and it still sends the client a 200 status code
</Route>

And here is my only express route:

app.use((req, res, next) => {
  const location = createLocation(req.url);
  const css = [];
  match({ routes, location }, (err, redirectLocation, renderProps) => {
    if (err) {
      //500 internal error
      return next(err);
    }
    if(redirectLocation){
      //react-router redirect, no problems here
      return res.redirect(redirectLocation.path + redirectLocation.query);
    }
    if (!renderProps){
      //404 not found
      let error = new Error();
      error.message = "Not Found";
      error.status = 404;
      return next(err);
    }

    res.status(200).end(getHtml(renderProps));
  }
}

//...
//some regular express error handler to log in console and (as of right now) send simple text to client.

while getHtml(renderProps) generates html with react's renderToString() on <RouterContext {...renderProps} />.

I want to somehow route to the error component, which will have access to the error code using the router context (or some other way) so it will show an appropiate error.

Any ideas?

2 Answers 2

1

I find this solution for 404 state on server-side render,

configure routes like this:

<Route component={Index} path="/">
  <IndexRoute component={Home} />
  <Route component={Chart} path="chart" />
  <Route component={Login} path="login" />
  <Route component={Error} path="*" notFound />
</Route>

And set express route like this:

app.use((req, res, next) => {
  const location = createLocation(req.url);
  const css = [];
  match({ routes, location }, (err, redirectLocation, renderProps) => {
    if (err) {
      //500 internal error
      return next(err);
    }
    if(redirectLocation){
      //react-router redirect, no problems here
      return res.redirect(redirectLocation.path + redirectLocation.query);
    }
    if (!renderProps){
      //404 not found
      let error = new Error();
      error.message = "Not Found";
      error.status = 404;
      return next(err);
    }

    const notFound = renderProps.routes.filter((route) => route.notFound).length > 0;
    res.status(notFound ? 404 : 200);

    res.end(getHtml(renderProps));
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, React Router has also updated theirs' docs to answer this question, see here: Server Rendering. They're pretty much saying what you wrote: "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."
0

I could be wrong, but give this a try:

if (!renderProps) {
  //404 not found
  let error = new Error();
  error.message = "Not Found";
  error.status = 404;
  res.status(error.status).end(someErrorHtml); // <- I think you are missing this
  return next(err);
}

1 Comment

My problem is with getting the html of the Index -> Error nested components, as described on the routes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.