Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
77
rated 0 times [  78] [ 1]  / answers: 1 / hits: 102526  / 6 Years ago, sun, august 19, 2018, 12:00:00

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
[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>
);
}
}


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;

More From » reactjs

 Answers
31

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!


[#53701] Wednesday, August 15, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
lamarmaximiliand

Total Points: 388
Total Questions: 104
Total Answers: 104

Location: Oman
Member since Fri, Dec 23, 2022
1 Year ago
;