登录 React.js 后重定向

Liv*_*aru 6 javascript reactjs react-router react-router-dom

几天以来,我一直在尝试在登录到主页后重定向我的用户,在我的 App.js 中创建一个回调函数,并通过 loginregisterpage 类组件将其作为道具发送到登录类组件,但这不起作用,有人可以吗看看它并告诉我我错过了什么?谢谢我的代码看起来像这样

应用程序.js

import React from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import { HomePage } from './Pages/HomePage/HomePage'
import { LoginRegisterPage } from './Pages/LoginRegisterPage/LoginRegisterPage'
import 'bootstrap/dist/css/bootstrap.min.css'

export class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      authenticated: false,
    }
    this.handleSuccess = this.handleSuccess.bind(this);

  }
  handleSuccess = (data) => {
    this.props.history.push("/")
  }

  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="/">
            <HomePage />
          </Route>
          <Route exact path="/login-register">
            <LoginRegisterPage onLoginSuccess={this.handleSuccess} />
        </Switch>
      </Router>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

LoginRegisterPage 类组件

class LoginPage extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            username: '',
            password: '',
            accessToken: '',
            authenticated: ''
        };
        this.handleChangeUsername = this.handleChangeUsername.bind(this);
        this.handleChangePassword = this.handleChangePassword.bind(this);

    }

    handleChangeUsername(event) {
        this.setState({
            username: event.target.value
        })
    }

    handleChangePassword(event) {
        this.setState({
            password: event.target.value
        })
    }

    handleClick(event) {
        var apiBaseUrl = "https://myapi.com/auth/"
        const payload = {
            method: "POST",
            headers: {
                'Content-Type': 'application/json; charset=utf-8'
            },
            body: JSON.stringify({
                'username': this.state.username,
                'password': this.state.password
            })
        };
        const { username, password } = this.state;

        if (username && password) {
            fetch(apiBaseUrl + 'login', payload)
                .then((response) => {
                    if (response.status === 200) {
                        alert("Logged In! You'll be redirected on Home")
                        return response.json()
                    } else {
                        return alert("wrong pass")
                    }
                }).then((data) => {
                    this.setState({
                        accessToken: data.accestToken,
                        authenticated: data.authenticated
                    });
                    localStorage.setItem('accessToken', data.accessToken);
                    if (data.authenticated === true) {
                        console.log(this.props)
                        this.props.onLoginSuccess(data)
                    }

                })
                .catch((err) => console.log(err));
        } else {
            alert("Cannot be Empty")
        }
    }

    render() {
        return (
            <div>
                <div className="form">
                    <div>
                        <div className="form-input">
                            <div >
                                <div className="userData">
                                    <span>
                                        <img
                                            src={UserIcon}
                                        />
                                    </span>
                                    <input
                                        autocomplete="off"
                                        type="text"
                                        name="username"
                                        placeholder="Username"
                                        value={this.state.username}
                                        onChange={this.handleChangeUsername}
                                    />
                                </div>
                                <div className="userData">
                                    <span>
                                        <img
                                            src={PasswordIcon}
                                        />
                                    </span>
                                    <input
                                        autocomplete="off"
                                        type="password"
                                        name="password"
                                        placeholder="Password"
                                        value={this.state.password}
                                        onChange={this.handleChangePassword}
                                    />
                                    <p style={(this.state.username && this.state.password) ? { display: 'none' } : { display: 'block' }}> Must fill all the form!</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="form-footer">
                    <img
                        src={Btn}
                        onClick={(event) => this.handleClick(event)}
                    />
                </div>
            </div>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

LoginPage 类组件

class LoginPage extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            username: '',
            password: '',
            accessToken: '',
            authenticated: ''
        };
        this.handleChangeUsername = this.handleChangeUsername.bind(this);
        this.handleChangePassword = this.handleChangePassword.bind(this);

    }

    handleChangeUsername(event) {
        this.setState({
            username: event.target.value
        })
    }

    handleChangePassword(event) {
        this.setState({
            password: event.target.value
        })
    }

    handleClick(event) {
        var apiBaseUrl = "https://movies-app-siit.herokuapp.com/auth/"
        const payload = {
            method: "POST",
            headers: {
                'Content-Type': 'application/json; charset=utf-8'
            },
            body: JSON.stringify({
                'username': this.state.username,
                'password': this.state.password
            })
        };
        const { username, password } = this.state;

        if (username && password) {
            fetch(apiBaseUrl + 'login', payload)
                .then((response) => {
                    if (response.status === 200) {
                        alert("Logged In! You'll be redirected on Home")
                        return response.json()
                    } else {
                        return alert("wrong pass")
                    }
                }).then((data) => {
                    this.setState({
                        accessToken: data.accestToken,
                        authenticated: data.authenticated
                    });
                    localStorage.setItem('accessToken', data.accessToken);
                    if (data.authenticated === true) {
                        console.log(this.props)
                        this.props.onLoginSuccess(data)
                    }

                })
                .catch((err) => console.log(err));
        } else {
            alert("Cannot be Empty")
        }
    }

    render() {
        return (
            <div>
                <div className="form">
                    <div>
                        <div className="form-input">
                            <div >
                                <div className="userData">
                                    <span>
                                        <img
                                            src={UserIcon}
                                        />
                                    </span>
                                    <input
                                        autocomplete="off"
                                        type="text"
                                        name="username"
                                        placeholder="Username"
                                        value={this.state.username}
                                        onChange={this.handleChangeUsername}
                                    />
                                </div>
                                <div className="userData">
                                    <span>
                                        <img
                                            src={PasswordIcon}
                                        />
                                    </span>
                                    <input
                                        autocomplete="off"
                                        type="password"
                                        name="password"
                                        placeholder="Password"
                                        value={this.state.password}
                                        onChange={this.handleChangePassword}
                                    />
                                    <p style={(this.state.username && this.state.password) ? { display: 'none' } : { display: 'block' }}> Must fill all the form!</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="form-footer">
                    <img
                        src={Btn}
                        onClick={(event) => this.handleClick(event)}
                    />
                </div>
            </div>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

Dre*_*ese 1

问题

App是在组件外部定义的,因此Router它没有history可调用的 prop 函数来进行任何导航。

解决方案

LoginRegisterPage组件在身份验证成功后进行导航。它将需要访问history最近上下文的对象Router。通常这是通过使用Route组件传递的路由属性来实现的。

你可以:

#1

移动由 的propLoginRegisterPage渲染,因此它接收路线 props,从而将对象作为 prop。componentRoutehistory

<Route exact path="/login-register" component={LoginRegisterPage} />
Run Code Online (Sandbox Code Playgroud)

登录注册页面

class LoginPage extends React.Component {
    constructor(props) {
        ...
    }

    ...

    handleClick(event) {
        var apiBaseUrl = "https://myapi.com/auth/"
        const payload = {...};
        const { username, password } = this.state;
        const { history } = this.props; // <-- destructure history from props

        if (username && password) {
            fetch(apiBaseUrl + 'login', payload)
                .then((response) => {
                    ...
                }).then((data) => {
                    this.setState({
                        accessToken: data.accestToken,
                        authenticated: data.authenticated
                    });
                    localStorage.setItem('accessToken', data.accessToken);
                    if (data.authenticated === true) {
                        console.log(this.props)
                        this.props.history.push("/"); // <-- navigate!
                    }

                })
                .catch((err) => console.log(err));
        } else {
            alert("Cannot be Empty")
        }
    }

    render() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

#2

LoginRegisterPage使用withRouter高阶组件装饰你的路由,以便将路由 props 作为 props 注入。

import { withRouter } from 'react-router-dom;

...

const LoginPageWithRouter = withRouter(LoginPage);
Run Code Online (Sandbox Code Playgroud)

笔记

如果您希望进行重定向,请将所有history.push调用替换为history.replace. push是一个正常的导航,并在历史状态上推送一条新路径,而replace替换堆栈中的当前历史条目。身份验证重定向后,您可能不希望用户返回到您的登录页面/路由。

编辑

如果您需要handleSuccess回调来管理某些身份验证状态,App那么我认为最好让App管理身份验证状态并LoginPage仍然处理导航。在这种情况下,请使用上面的第二个解决方案,以便它同时接收handleSuccess回调和history对象。

if (data.authenticated === true) {
  this.props.onLoginSuccess(data); // <-- callback to parent to set state
  this.props.history.replace("/"); // <-- imperative navigation
}
Run Code Online (Sandbox Code Playgroud)