登录时重定向 - React.js [英] Redirect on Login - React.js

查看:19
本文介绍了登录时重定向 - React.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的用户成功登录后(在 Login.js 内),我试图用 React Router 做一个简单的重定向,并阻止用户重新访问登录页面(在 index.js 内).

在 Login.js 中,我在登录按钮标签中有 onSubmit={this.handleSubmit} 和用于重定向的 handleSubmit(e) 函数.我在网上尝试了一些其他的解决方案,但我认为我对 组件的用法的理解是错误的.

在 index.js 中,我有一个条件来测试用户是登录还是未登录,并(很差地)提醒用户为什么他们无法访问所需的页面.我在 Youtube 视频中看到了这个,但不确定这是否是获得预期效果的最佳方式.

目前,当我登录成功时,警报如果您已登录,则无法登录!已设置,但我显然不希望成功后立即关闭警报登录,我希望重定向首先触发.如果我交换括号中的两个,React 会抛出错误.

如何在成功登录后立即触发重定向,但不发送警报如果您已登录,则无法登录!?

Login.js 组件:

import React, { Component } from 'react';从../config/Fire.js"导入火;从'react-router-dom'导入{链接,重定向};从反应密码掩码"导入密码掩码;导出默认类登录扩展组件{构造函数(道具){超级(道具);this.login = this.login.bind(this);this.handleChange = this.handleChange.bind(this);this.handleSubmit = this.handleSubmit.bind(this);this.signup = this.signup.bind(this);this.state = {电子邮件: '',密码: ''};}句柄变化(e){this.setState({ [e.target.name]: e.target.value });}处理提交(e){e.preventDefault();<重定向到="/ticket-list"/>;}登录(e){e.preventDefault();fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password).catch((error) => {警报(错误);});}注册(e){e.preventDefault();fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).catch((error) => {警报(错误);})}使成为() {返回 (<div className="m-container"><h1>登录</h1><小时/><div className="m-container"><form onSubmit={this.submitForm}><div><label for="exampleInputEmail1">电子邮件地址:</label><br/><输入值={this.state.email}onChange={this.handleChange}类型=文本"名称=电子邮件"id="exampleInputEmail1"placeholder="you@email.com"/>

<div><label for="exampleInputPassword1">密码:</label><br/>{/* 显示和隐藏密码时的边距问题 */}<密码掩码值={this.state.password}onChange={this.handleChange}类型=密码"名称=密码"id="exampleInputPassword1"占位符=************"/>

<br/><按钮类型=提交"类名=按钮"onClick={this.login}onSubmit={this.handleSubmit}>登录</button>&nbsp;<Link className="button-inv" to="/register">注册</Link></表单>

);}}

index.js 组件:

import React, { Component } from 'react';从'react-router-dom'导入{路由,开关,重定向};从'./Home'导入首页;从'./Technician'导入技术员;从'./About'导入关于;从'./Register'导入注册;从 './Login' 导入登录;从'./TicketList'导入TicketList;导出默认类路由扩展组件{使成为() {返回 (<开关><Route path="/" 精确组件={Home}/><Route path="/technician" 精确组件={Technician}/><Route path="/about" 精确组件={About}/><Route path="/register" 精确渲染={()=>(this.props.user ?(alert("如果您已登录,则无法注册!"), (<Redirect to="/"/>)) :(<Register/>))}/><Route path="/login" 精确渲染={()=>(this.props.user ?(alert("如果您已登录,则无法登录!"), (<Redirect to="/ticket-list"/>)) :(<登录/>))}/><Route path="/ticket-list" 精确渲染={()=>(this.props.user ?(<TicketList/>) : (alert("您必须登录才能访问此页面."), (<Redirect to="/login"/>)))}/></开关>);}};

App.js:

import React, { Component } from 'react';从'react-router-dom'导入{ BrowserRouter};从'./routes'导入路由;从'./config/Fire.js'导入火;//CSS导入'./assets/css/App.css';导入'./assets/css/Header.css';导入'./assets/css/Footer.css';//组件从'./components/Header'导入标题;从'./components/Footer'导入页脚;类 App 扩展组件 {构造函数(道具){超级(道具);this.state = {用户:{},}}//当组件第一次完成渲染时componentDidMount(){this.authListener();}//如果用户登录 (if) 或退出 (else) 则调用authListener() {fire.auth().onAuthStateChanged((user) => {//console.log(用户);如果(用户){this.setState({用户});} 别的 {this.setState({ 用户: null });}});}使成为() {返回 (<浏览器路由器><div className="包装器"><标题用户={this.state.user}/><div className="body"><路由用户={this.state.user}/>

<页脚/>

</BrowserRouter>);}}导出默认应用程序;

解决方案

要解决您的问题,您必须为 Login/Register 创建单独的组件并进行警报和重定向这取决于用户.您将需要 react-router 库中名为 withRouter 的高阶组件.

登录容器:

class LoginContainer 扩展组件 {构造函数(道具){超级(道具)如果(道具.用户){alert("登录后无法登录!")props.history.push('/ticket-list')}}使成为() {返回<登录/>;}}导出默认 withRouter(LoginContainer)

然后在您的 Routes 中像这样使用它:

<LoginContainer user={this.props.user}/>}/>

Register 相同,或者您可以制作一个并获取诸如 alertMessageredirectTo 之类的参数,并使用它们而不是硬编码值.

此外,我建议您将 auth HoC 用于您的私有路由,未经身份验证无法访问.

我更喜欢使用新的上下文 API 来共享用户、本地化等实体,所以这里是一个如何使用 React Context API 制作 PrivateRoute 的示例.

App.js

<代码>...export const UserContext = React.createContext();...类 App 扩展组件 {状态 = {用户:空}componentDidMount() {this.authListener();}authListener() {fire.auth().onAuthStateChanged(user => {如果(用户){this.setState({用户});}});}使成为() {<UserContext.Provider value={this.state}><浏览器路由器>//其他东西 Switch 等...</BrowserRouter></UserContext.Provider>}}

PrivateRoute.jsx

import React, { Component } from 'react';从'react-router-dom'导入{路由,重定向}从 './App' 导入 { UserContext }const PrivateRoute = ({ component: ComposedComponent, ...rest }) =>{类身份验证扩展组件{handleRender = 道具 =>{如果(!this.props.user){return <Redirect to="/login"/>} 别的 {return <ComposedComponent user={this.props.user} {...props}/>}}使成为() {返回 (<Route {...rest} render={this.handleRender}/>);}}返回 (<UserContext.Consumer>{({用户}) =><认证用户={user}/>}</UserContext.Consumer>)};导出默认的 PrivateRoute

然后你可以使用 PrivateRoute 而不是 Route 以防你不想在没有身份验证的情况下显示页面.

从 './PrivateRoute' 导入 PrivateRoute...//所有组件代码使成为() {...<开关><PrivateRoute path="/ticket-list" component={<TicketList/>}/></开关>...}

希望有帮助!祝你好运!

I am trying to do a simple Redirect with React Router after my user successfully logs in (inside Login.js), and prevent the user from revisiting the login page (inside index.js).

In Login.js, I have onSubmit={this.handleSubmit} within the login button tag, and handleSubmit(e) function to Redirect. I have tried a few other solutions online, but I think my understanding on the usage of the <Redirect/> component is wrong.

In index.js, I have a conditional that tests if the user is signed in, or not signed in, and (poorly) alerts the user on why they can't visit the desired page. I saw this in a Youtube video, but not sure if it's the best way to get the desired effect.

Currently, when I log in successfully, the alert You can't login if you are logged in! is set off, but I obviously don't want the alert going off right after a successful login, I want the Redirect to trigger first. If I swap the two in the parenthesis, React throws an error.

How do I get the Redirect to trigger right after a successful login, but not send the alert You can't login if you are logged in!?

Login.js Component:

import React, { Component } from 'react';
import fire from '../config/Fire.js';
import { Link, Redirect } from 'react-router-dom';
import PasswordMask from 'react-password-mask';

export default class Login extends Component {
    constructor(props) {
        super(props);
        this.login = this.login.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.signup = this.signup.bind(this);
        this.state = {
          email: '',
          password: ''
        };
      }

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

    handleSubmit(e) {
        e.preventDefault();
        <Redirect to="/ticket-list"/>;
    }

    login(e) {
        e.preventDefault();
        fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password).catch((error) => {
            alert(error);
            });
    }

    signup(e){
        e.preventDefault();
        fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).catch((error) => {
            alert(error);
            })
    }

    render() {
        return (
        <div className="m-container">
            <h1>Login</h1>
            <hr/>
            <div className="m-container">
                <form onSubmit={this.submitForm}>
                <div>
                    <label for="exampleInputEmail1">Email address: </label>
                    <br/>
                    <input 
                    value={this.state.email} 
                    onChange={this.handleChange} 
                    type="text" 
                    name="email" 
                    id="exampleInputEmail1" 
                    placeholder="you@email.com" />
                </div>
                <div>
                    <label for="exampleInputPassword1">Password: </label>
                    <br/>
                    {/* Margin issue when showing and hiding password */}
                    <PasswordMask 
                    value={this.state.password} 
                    onChange={this.handleChange} 
                    type="password" 
                    name="password" 
                    id="exampleInputPassword1" 
                    placeholder="**********"
                     />
                </div>
                <br/>
                <button 
                    type="submit" 
                    className="button" 
                    onClick={this.login}
                    onSubmit={this.handleSubmit}>Login</button>
                &nbsp;
                <Link className="button-inv" to="/register">Register</Link>
                </form>
            </div>
        </div>
        );
    }
}

index.js Component:

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

import Home from './Home';
import Technician from './Technician';
import About from './About';
import Register from './Register';
import Login from './Login';
import TicketList from './TicketList';

export default class Routes extends Component {

    render() {
        return (
        <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/technician" exact component={Technician} />
            <Route path="/about" exact component={About} />
            <Route path="/register" exact render={()=>(
                this.props.user ? (alert("You can't register if you are logged in!"), (<Redirect to="/"/>)) : (<Register/>)
            )} />
            <Route path="/login" exact render={()=>(
                this.props.user ? (alert("You can't login if you are logged in!"), (<Redirect to="/ticket-list"/>)) : (<Login/>)
            )} />
            <Route path="/ticket-list" exact render={()=>(
                this.props.user ? (<TicketList/>) : (alert("You must log in to visit this page."), (<Redirect to="/login"/>))
            )} />
        </Switch>
        );
    }
};

App.js:

import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom';
import Routes from './routes';
import fire from './config/Fire.js';

// CSS
import './assets/css/App.css';
import './assets/css/Header.css';
import './assets/css/Footer.css';
// Components
import Header from './components/Header';
import Footer from './components/Footer';

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      user:{},
    }
  }

  //When component is done rendering for the first time
  componentDidMount(){
    this.authListener();
  }

  // If user logs in (if) or out (else) this is called
  authListener() {
    fire.auth().onAuthStateChanged((user) => {
      //console.log(user);
      if (user) {
        this.setState({ user });
      } else {
        this.setState({ user: null });
      }
    });
  }


  render() {
    return (
      <BrowserRouter>
        <div className="wrapper">
          <Header user={this.state.user} />
          <div className="body">
            <Routes user={this.state.user} />
          </div>
          <Footer />
        </div>
      </BrowserRouter>
    );
  }
}

export default App;

解决方案

To solve your problem you have to create separate components for Login/Register and make alerts and redirects there depends on user. You will need High Order Component named withRouter from react-router lib.

Login container:

class LoginContainer extends Component {
  constructor(props) {
    super(props)

    if (props.user) {
      alert("You can't login if you are logged in!")
      props.history.push('/ticket-list')
    }
  }

  render() {
    return <Login />;
  }
}

export default withRouter(LoginContainer)

And then use it in your Routes like this:

<Route path="/login" render={()=> <LoginContainer user={this.props.user} />} />

The same one for Register or you can just make one and get params like alertMessage and redirectTo and use them instead of hardcoded values.

In addition, I advice you to use auth HoC for your private routes, which is not accessible without authentication.

I'd prefer to use new context API for sharing such entity as user, localization, etc, so here is an example how to make PrivateRoute using React Context API.

App.js

...
export const UserContext = React.createContext();
...
class App extends Component {

    state = {
        user: null
    }

    componentDidMount() {
      this.authListener();
    }

    authListener() {
      fire.auth().onAuthStateChanged(user => {
        if (user) {
          this.setState({ user });
        }
      });
    }

    render() {
       <UserContext.Provider value={this.state}>
           <BrowserRouter>
               // another things Switch etc
               ...
           </BrowserRouter>
       </UserContext.Provider>
    }
}

PrivateRoute.jsx

import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom'
import { UserContext } from './App'

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

  class Authentication extends Component {

    handleRender = props => {
      if (!this.props.user) {
        return <Redirect to="/login" />
      } else {
        return <ComposedComponent user={this.props.user} {...props} />
      }
    }

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

  return (
    <UserContext.Consumer>
      {
        ({ user }) => <Authentication user={user} />
      }
    </UserContext.Consumer>
  )
};

export default PrivateRoute

And then you can use PrivateRoute instead of Route in case when you don't want to show page without authentication.

import PrivateRoute from './PrivateRoute'

...

// all of the component code
render() {
    ...
    <Switch>
        <PrivateRoute path="/ticket-list" component={<TicketList />} />
    </Switch>
    ...
}

Hope it helps! Good luck!

这篇关于登录时重定向 - React.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆