web-dev-qa-db-fra.com

Rediriger à la connexion - React.js

J'essaie de faire une simple redirection avec React Router après que mon utilisateur s'est connecté avec succès (dans Login.js), et d'empêcher l'utilisateur de revoir la page de connexion (dans index.js).

Dans Login.js, j'ai onSubmit={this.handleSubmit} Dans la balise du bouton de connexion, et la fonction handleSubmit(e) pour rediriger. J'ai essayé quelques autres solutions en ligne, mais je pense que ma compréhension de l'utilisation du composant <Redirect/> Est erronée.

Dans index.js, j'ai une conditionnelle qui teste si l'utilisateur est connecté ou non, et alerte (mal) l'utilisateur sur les raisons pour lesquelles il ne peut pas visiter la page souhaitée. J'ai vu cela dans une vidéo Youtube, mais je ne sais pas si c'est la meilleure façon d'obtenir l'effet souhaité.

Actuellement, lorsque je me connecte avec succès, l'alerte You can't login if you are logged in! Est déclenchée, mais je ne veux évidemment pas que l'alerte se déclenche juste après une connexion réussie, je veux que la redirection se déclenche en premier. Si j'échange les deux entre parenthèses, React renvoie une erreur.

Comment puis-je faire en sorte que la redirection se déclenche juste après une connexion réussie, sans envoyer l'alerte You can't login if you are logged in!?

Composant Login.js:

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="[email protected]" />
                </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>
        );
    }
}

Composant index.js:

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;
3
douglasrcjames

Pour résoudre votre problème, vous devez créer des composants distincts pour Login/Register et créer des alertes et des redirections selon l'utilisateur. Vous aurez besoin d'un composant d'ordre élevé nommé withRouter de react-router lib.

Conteneur de connexion:

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)

Et puis utilisez-le dans votre Routes comme ceci:

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

Le même pour Register ou vous pouvez simplement en créer un et obtenir des paramètres comme alertMessage et redirectTo et les utiliser à la place des valeurs codées en dur.

De plus, je vous conseille d'utiliser l'auth HoC pour vos itinéraires privés, qui n'est pas accessible sans authentification.

Je préfère utiliser une nouvelle API de contexte pour partager une entité telle que l'utilisateur, la localisation, etc., voici donc un exemple comment faire PrivateRoute en utilisant 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

Et puis vous pouvez utiliser PrivateRoute au lieu de Route au cas où vous ne voulez pas afficher la page sans authentification.

import PrivateRoute from './PrivateRoute'

...

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

J'espère que ça aide! Bonne chance!

3
Denys Kotsur

Vous pouvez utiliser:

<Redirect Push to="/somewhere/else"/>
2
Olusola Omosola

comme le dit la documentation officielle, vous devez créer un routeur privé

ceci est un exemple de la façon dont je l'implémente en utilisant le stockage local pour voir si les données utilisateur sont là ou non, puis rediriger vers la page de connexion si les données ne sont pas là. cela peut être réutilisé dans tous vos composants!

import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';

import Login from './views/login';
import Supportedmodels from './views/dashboard/supported-models';


const PrivateRoute = ({ component: Component, ...rest }) => 
(  
  <Route {...rest} render={props => 
  (
    localStorage.getItem('user') ? <Component {...props} /> : <Redirect to={{pathname: '/login'}}/>
  )}/>
);

function App() 
{
  return (

    <Router>
      <Switch>
        <PrivateRoute path="/" component={Supportedmodels} exact />

        <Route path="/login" component={Login} />
      </Switch>      
    </Router>
  );
}

pour en savoir plus, voici le lien https://reacttraining.com/react-router/web/example/auth-workflow

0
jerryurenaa