Authenticate async with react-router-v4

前端 未结 3 1445
醉酒成梦
醉酒成梦 2020-12-15 08:29

I have this PrivateRoute component (from the docs):

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

        
相关标签:
3条回答
  • 2020-12-15 08:44

    In case anyone's interested in @CraigMyles implementation using hooks instead of class component:

    export const PrivateRoute = (props) => {
        const [loading, setLoading] = useState(true);
        const [isAuthenticated, setIsAuthenticated] = useState(false);
    
        const { component: Component, ...rest } = props;
    
        useEffect(() => {
            const fetchData = async () => {
                const result = await asynCall();
    
                setIsAuthenticated(result);
                setLoading(false);
            };
            fetchData();
        }, []);
    
        return (
            <Route
                {...rest}
                render={() =>
                    isAuthenticated ? (
                        <Component {...props} />
                    ) : loading ? (
                        <div>LOADING...</div>
                    ) : (
                        <Redirect
                            to={{
                                pathname: "/login",
                                state: { from: props.location },
                            }}
                        />
                    )
                }
            />
        );
    };
    
    
    

    Which works great when called with:

    <PrivateRoute path="/routeA" component={ComponentA} />
    <PrivateRoute path="/routeB" component={ComponentB} />
    
    0 讨论(0)
  • 2020-12-15 08:46

    If you aren't using Redux or any other kind of state management pattern you can use the Redirect component and components state to determine if the page should render. This would include setting state to a loading state, making the async call, after the request has completed save the user, or lack of user to state and render the Redirect component, if criteria is not met the component will redirect.

    class PrivateRoute extends React.Component {
      state = {
        loading: true,
        isAuthenticated: false,
      }
      componentDidMount() {
        asyncCall().then((isAuthenticated) => {
          this.setState({
            loading: false,
            isAuthenticated,
          });
        });
      }
      render() {
        const { component: Component, ...rest } = this.props;
        if (this.state.loading) {
          return <div>LOADING</div>;
        } else {
          return (
            <Route {...rest} render={props => (
              <div>
                {!this.state.isAuthenticated && <Redirect to={{ pathname: '/login', state: { from: this.props.location } }} />}
                <Component {...this.props} />
              </div>
              )}
            />
          )
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-15 08:56

    @pizza-r0b's solution worked perfectly for me. However, I had to amend the solution slightly to prevent the loading div from being displayed multiple times (once for every PrivateRoute defined within the app) by rendering the loading div inside - instead of outside - the Route (similar to React Router's auth example):

    class PrivateRoute extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          loading: true,
          isAuthenticated: false
        }
      }
    
      componentDidMount() {
        asyncCall().then((isAuthenticated) => {
          this.setState({
            loading: false,
            isAuthenticated
          })
        })
      }
    
      render() {
        const { component: Component, ...rest } = this.props
        return (
          <Route
            {...rest}
            render={props =>
              this.state.isAuthenticated ? (
                <Component {...props} />
              ) : (
                  this.state.loading ? (
                    <div>LOADING</div>
                  ) : (
                      <Redirect to={{ pathname: '/login', state: { from: this.props.location } }} />
                    )
                )
            }
          />
        )
      }
    }
    

    An extract from my App.js for completeness:

    <DashboardLayout>
      <PrivateRoute exact path="/status" component={Status} />
      <PrivateRoute exact path="/account" component={Account} />
    </DashboardLayout>
    
    0 讨论(0)
提交回复
热议问题