react - react router - privateRoute - 无限循环

时间:2018-05-23 13:16:19

标签: javascript reactjs react-router infinite-loop

我试图在单页应用程序中创建一个简单的身份验证系统。 我想禁用execpt /login的所有路由。 了解用户是否经过身份验证的方式或了解访客是否知道access_token中是否有localStorage

当我启动应用时,Main组件已启动。该组件通过检查localStorage

来定义路由并知道用户是否经过身份验证

默认路由(/)用于呈现Home组件,但与反应路由器example一样,Home组件是受PrivateRoute对象保护。

PrivateRoute对象检查用户是否经过身份验证。如果是,则呈现Home组件,否则用户将被重定向到login的{​​{1}}组件。

如果成功,/login组件会将用户重定向到Login并执行回调以提供/

access_token组件定义了回调,它将Main保存在access_token中,并更改localStorage以将用户声明为已通过身份验证。现在,用户可以访问state组件。

我的问题是,Home系统始终将用户检查为访客,因此它总是重定向到PrivateRoute。但是当/login access_token localStorageLogin重定向到受Home保护的PrivateRoute时,尽管{{1} handleLogin,这是一个infite循环回调。

你能找到解决方案吗?

Main.jsx

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Link, Redirect, Route} from "react-router-dom";
import {Login} from "./Login"
import {Home} from "./Home";


class Main extends Component {
    constructor(props) {
        super(props);

        this.handleLogout = this.handleLogout.bind(this);
        this.handleLogin = this.handleLogin.bind(this);
        this.state = {authed: localStorage.getItem('access_token') !== null};
    }

    componentDidCatch(error, info) {
    }

    handleLogout(event) {
        event.preventDefault();
        localStorage.removeItem('access_token');
        this.setState({authed: false});
    }

    handleLogin(token) {
        localStorage.setItem('access_token', token);
        this.setState({authed: token !== null});
    }

    render() {
        const PrivateRoute = ({component: Component, ...rest}) => (
            <Route {...rest} render={props =>
                this.state.authed()
                    ? (<Component {...props} />)
                    : (<Redirect to="/login"/>)
            }
            />
        );

        const LoginLogout = () => {
            return this.state.authed
                ? (<button onClick={this.handleLogout}>Logout</button>)
                : (<Link to="/login">Login</Link>);
        };

        return (
            <BrowserRouter>
                <div>
                    <ul>
                        <li>
                            <Link to="/">Home</Link>
                        </li>
                        <li>
                            <LoginLogout/>
                        </li>
                    </ul>

                    <Route path="/login" component={() => <Login handleLogin={this.handleLogin}/>}/>
                    <PrivateRoute exact path="/" component={Home}/>

                </div>
            </BrowserRouter>
        );
    }
}

if (document.getElementById('main')) {
    ReactDOM.render(<Main/>, document.getElementById('main'));
}

Login.jsx

import React, {Component} from 'react';
import {Redirect} from "react-router-dom";

export class Login extends Component {

    constructor(props) {
        super(props);

        this.state = {
            email: '',
            password: '',
            redirect: localStorage.getItem('access_token') !== null,
            token: null,
            loading: false,
            error: null
        };
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    componentWillUnmount() {
        this.props.handleLogin(this.state.token);
    }

    handleInputChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        this.setState({
            [name]: value
        });
    }

    handleSubmit(event) {
        event.preventDefault();
        this.setState({
            error: null,
            loading: true
        });
        axios.post('/api/login', {
            'client_id': '3',
            'email': this.state.email,
            'password': this.state.password,
            'confirm_password': this.state.password
        }).then((response) => {
            let token = response.data.access_token;
            this.setState({
                redirect: true,
                token: token,
                loading: false
            });
        }, (error) => {
            console.error('error', error.response.data);
            this.setState({
                error: error.response.data,
                loading: false
            });
        });
    }

    render() {

        if (this.state.redirect)
            return (<Redirect to={"/"}/>);

        return (
            <form onSubmit={this.handleSubmit}>
                <label htmlFor="email">Email :</label>
                <input type="text" name="email" id="email" value={this.state.email} onChange={this.handleInputChange}
                       disabled={this.state.loading}/>
                <label htmlFor="password">Password :</label>
                <input type="password" name="password" id="password" value={this.state.password}
                       onChange={this.handleInputChange} disabled={this.state.loading}/>
                <button type="submit"
                        disabled={this.state.loading}>{this.state.loading ? "..." : "Se connecter"}</button>
                {this.state.error && (
                    <div>
                        <p>Erreur : {JSON.stringify(this.state.error)}</p>
                    </div>
                )}
            </form>
        );
    }
}

1 个答案:

答案 0 :(得分:1)

/resource/example-ebook-request/thank-you/ /resource/research-report-2018/thanks/ /some-other-ebook-no-resource-subfolder/ 功能中,您需要从道具中调用handleSubmit,以便在容器组件中正确更新状态。

handleLogin

这样,您的 handleSubmit(event) { ... .then((response) => { let token = response.data.access_token; this.setState({ redirect: true, token: token, loading: false }); // here, call the handle from props this.props.handleLogin(token); } ... 将具有正确的值