Redirection when typing in links manually, other i

2019-08-22 05:45发布

问题:

I'm facing an issue in my app, when the user is authenticated and he types in the desired link address manually, which he has access to, the page redirects him to the home page. This doesn't happen when simply clicking on the links.

Here is the code:

const asyncCheckout = asyncComponent(() => {
    return import('./containers/Checkout/Checkout');
});

const asyncOrders = asyncComponent(() => {
    return import('./containers/Orders/Orders');
});

const asyncAuth = asyncComponent(() => {
    return import('./containers/Auth/Auth');
});

class App extends Component {
    componentDidMount() {
        this.props.onTryAutoSignup();
    }

    render() {
        let routes = (
            <Switch>
                <Route path="/auth" component={asyncAuth} />
                <Route path="/" exact component={BurgerBuilder} />
                <Redirect to="/" />
            </Switch>
        );

        console.log('Is authenticated: ' + this.props.isAuthenticated);
        console.log(routes.props.children);


        if (this.props.isAuthenticated) {
            routes = (
                <Switch>
                    <Route path="/checkout" component={asyncCheckout} />
                    <Route path="/orders" component={asyncOrders} />
                    <Route path="/logout" component={Logout} />
                    <Route path="/auth" component={asyncAuth} />
                    <Route path="/" exact component={BurgerBuilder} />
                    <Redirect to="/" />
                </Switch>
            );

        }

        console.log('Is authenticated: ' + this.props.isAuthenticated);
        console.log(routes.props.children);

        return (
            <div>
                <Layout>
                    {routes}
                </Layout>
            </div>
        );
    }
}

const mapStateToProps = state => {
    return {
        isAuthenticated: state.auth.token !== null
    };
};

const mapDispatchToProps = dispatch => {
    return {
        onTryAutoSignup: () => dispatch(actions.authCheckState())
    };
};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));

Here is what the console.logs show, when manually typing in the links:

Is authenticated: false
App.js:38 Array(3)
App.js:55 Is authenticated: false
App.js:56 Array(3)
App.js:37 Is authenticated: true
App.js:38 Array(3)
App.js:55 Is authenticated: true
App.js:56 Array(6)

It seems like it does this, because when manually typing in addresses, the page has to reload, and that's why user will always be unauthenticated at first.

I tried messing with the props that the react-router giveds us in order to somehow still successfully redirect the user to the correct page, but the this.props.match.url and this.props.match.path is always set to "/", even when clicking on links.

So my two questions are:

  1. How should I handle the redirection, when the user manually types in the desired address, when he is authenticated (token is set in localStorage)?
  2. How should I fix the react-router situation?

回答1:

Actually, you should perform this action on init of your application. For instance, in index.js file.

Like this - index.js file:

....
const store = createStoreWithMiddleware(reducers);
const token = localStorage.getItem('token');
if (token) {
  store.dispatch(authCheckState());
}
...

So every time when your application is loaded it will check status of current user and your containers will get updated information.

Also, I prefer to use authorization HoC instead of overriding routes.

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Route, Redirect} from 'react-router-dom'

export const PrivateRoute = ({component: ComposedComponent, ...rest}) => {

  class Authentication extends Component {

    /* Redirect if not authenticated; otherwise, return the component imputted into <PrivateRoute /> */
    handleRender = props => {
      if (!this.props.isAuthenticated) {
        return <Redirect to="auth" />
      } else {
        return <ComposedComponent {...props}/>
      }
    }

    render() {
      return (
        <Route {...rest} render={this.handleRender}/>
      );
    }
  }

  const mapStateToProps = state => {
    return {
      isAuthenticated: state.auth.token !== null
    };
  }

  const AuthenticationContainer = connect(mapStateToProps)(Authentication);
  return <AuthenticationContainer/>
};

And then in your routes you can just use this HoC to check if user is logged in before it will access to the particular route:

<Switch>
    <PrivateRoute path="/checkout" component={asyncCheckout}/>
    <PrivateRoute path="/orders" component={asyncOrders}/>
    <PrivateRoute path="/logout" component={Logout}/>
    <Route path="/auth" component={asyncAuth}/>
    <Route path="/" exact component={BurgerBuilder}/>
    <Redirect to="/" />
</Switch>


回答2:

Reactjs apps are client side apps, ie, once the JavaScript is downloaded, the client handles everything, even the address in the address bar.

The thing is the server doesn't know about this. But, once u send something through address bar, the server thinks that some request is made, it doest know what to do, hence it sends the index.html file back, which triggers showing of homepage.

First thing, read this answer React-router urls don't work when refreshing or writing manually

This will give you more info about how to handle such situations.

Second thing is that u should check whether a user is authenticated or not at the start of the app, and then redirect them.