Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect after login React.js

i've been trying since days to redirect my user after login to the home creating a callback function in my App.js and sending it as props to the login class component throught a loginregisterpage class component, but this doesn't work, can someone have a look on it and tell me what i;m missing out? Thank you my code look like this

App.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>
    )
  }
}

LoginRegisterPage class component

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

LoginPage class component

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>
        );
    }
}
like image 897
Liviu Cojocaru Avatar asked Feb 09 '21 08:02

Liviu Cojocaru


People also ask

How do I redirect after authentication?

The most common ways to implement redirection logic after login are: using HTTP Referer header. saving the original request in the session. appending original URL to the redirected login URL.

How do I redirect in react JS?

The Redirect component was usually used in previous versions of the react-router-dom package to quickly do redirects by simply importing the component from react-router-dom and then making use of the component by providing the to prop, passing the page you desire to redirect to.

How do I redirect to another page in react?

To redirect to another page on button click in React: Use the useNavigate() hook, e.g. const navigate = useNavigate(); . Call the navigate() function, passing it the path - navigate('/about') . The navigate() function lets us navigate programmatically.


2 Answers

If you're using React Router you can use the Redirect component:

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

export default function PrivateRoute () {
  if (notLoggedIn()) {
    return <Redirect to="/login"/>;
  }
  // return your component
}

But if you're not inside a render function (i.e. you're in a submit callback) or you want to rewrite browser history, use the useHistory hook (note: hooks work only in function components, not class components)

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


const history = useHistory();

// After your login action you can redirect with this command:
history.push('/otherRoute');

like image 166
T30 Avatar answered Oct 19 '22 17:10

T30


Issue

App is defined outside the Router component so it has no history prop function to call to do any navigation.

Solution

Have the LoginRegisterPage component navigate upon successful authentication. It will need to access the history object of the nearest Router context. Normally this is achieved by consuming passed route props from the Route component.

You can:

#1

Move LoginRegisterPage to be rendered by the component prop of the Route so it receives the route props and thus the history object as a prop.

<Route exact path="/login-register" component={LoginRegisterPage} />

LoginRegisterPage

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() {
        ...
    }
}

#2

Decorate your LoginRegisterPage with the withRouter Higher Order Component so the route props are injected as props.

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

...

const LoginPageWithRouter = withRouter(LoginPage);

Note

If you prefer to do a redirect then replace any history.push calls with history.replace. push is a normal navigation and pushes on a new path on the history state whereas replace replaces the current history entry in the stack. After the auth redirect you probably don't want users to back navigate back to your login page/route.

Edit

If you need the handleSuccess callback to manage some auth state in App then I think it best to let App manage the authentication state and the LoginPage to still handle navigation. In this case, go with the second solution above so it receives both the handleSuccess callback and the history object.

if (data.authenticated === true) {
  this.props.onLoginSuccess(data); // <-- callback to parent to set state
  this.props.history.replace("/"); // <-- imperative navigation
}
like image 1
Drew Reese Avatar answered Oct 19 '22 18:10

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!