remix-run / react-router

Declarative routing for React
https://reactrouter.com
MIT License
53.11k stars 10.31k forks source link

How to use redirectLocation on server side rendering? #1989

Closed coma closed 9 years ago

coma commented 9 years ago

I know that you are working on the docs for the upcoming version but I'm really curious about the redirectLocation argument on the match method... Is there a way of reaching it from a component like using transitionTo or something like that?

mykhailo-riabokon commented 9 years ago

I am also interesting in this question

fantasy8-me commented 9 years ago

+1,

In 1.0.0-beta3, I try transitionTo , got below error

Router#transitionTo is client-side only (needs history)

After upgrade to 1.0.0-rc1, change transitionTo to this.props.history.pushState(null,/login')`, no error more, but the redirection doesn't happen.

So would like to know whether this is supported in 1.0.0-rc1, and how.

BTW, IMO, two types of redirect can be supported in server side

  1. '302' redirect,
  2. Just forward to another route, without response a '302' to server
coma commented 9 years ago

I'm redirecting on the server using a custom error:

class RedirectError extends Error {

    constructor (url, status) {

        super('Redirecting to "' + url + '" after error.');
        this.url = url;
        this.status = status || 301;
    }
}

export default RedirectError;

thrown in the constructor method of one of my components like:

class SomeView extends React.Component {

    constructor (props, context) {

        super(props, context);

        if (!context.data.session) {

            throw new RedirectError('login');

        } else {

            this.context = context;
            this.state   = context.data.session;
        }
    }
}

and handled from Koa like:

try {

    var data = yield new Promise(resolve => fetch(renderProps.params, this.session, resolve));
    this.type = 'text/html';
    this.body = render(renderProps, data);

} catch (error) {

    if (error instanceof RedirectError) {

        this.status = error.status;
        this.redirect(error.url);

    } else {

        this.status = 500;
        this.type   = 'text/html';
        this.body   = error.message;
    }
}

and on the browser like:

try {

    ReactDOM.render(<DataWrapper data={ data }><Router history={ history }>{ routes }</Router></DataWrapper>, document.getElementById('app'));

} catch (error) {

    if (error instanceof RedirectError) {...

does it make sense or should I wait for some way to trigger that redirectLocation instead?

mjackson commented 9 years ago

If you get a redirectLocation in your match callback, it means that one of your onEnter hooks redirected the request somewhere else. So you probably need to issue a 302 HTTP response with the new location in the Location header.

coma commented 9 years ago

Thanks @mjackson