Reactjs - Login redirect but has Invalid Hook Call

Viewed 188

My goal here is to redirect the login to dashboard after a successful response. However, I am getting

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

I have imported useHistory from react-router-dom but cannot initialize it inside the body of the LoginPage. All I would like to achieve is to redirect to the dashboard page.

Login.js

import React, { Component } from 'react';
import { useHistory } from "react-router-dom";

export class Login extends Component {

    static displayName = Login.name;

    constructor(props) {

        super(props);

        this.state = {
            username: '',
            password: '',
            errors: {},
            submitted: false
        }

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);

    }

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

    handleSubmit(e) {
        e.preventDefault();

        //const history = useHistory();
        this.setState({ submitted: true });
        const { username, password } = this.state;
        const { dispatch } = this.props;
        let errors = {};

        if (username == "admin" && password == "admin") {

            //history.push('/dashboard');
            console.log("Logged-in");

        } else {

            errors["credentials"] = "You have entered the wrong username or password.";

        }

        this.setState({
            errors: errors
        });

    }


    render = () => {
        const history = useHistory();
        const { loggingIn } = this.props;
        const { username, password, submitted } = this.state;
        return (
            <div className="col-md-6 col-md-offset-3">
                <h1>Login</h1>
                <form name="form" onSubmit={this.handleSubmit}>
                    <div className={'form-group' + (submitted && !username ? 'has-error' : '')}>
                        <label>Username</label>
                        <input type="text" className="form-control" name="username" value={username} onChange={this.handleChange} placeholder="Username" />
                        {submitted && !username &&
                            <div className="error">Username is required</div>
                        }
                    </div>
                  

                    <div className="form-group mt-3">
                        <label>Password</label>
                        <input type="password" className="form-control" name="password" value={password} onChange={this.handleChange} placeholder="Password" />
                        {submitted && !password &&
                            <div className="error">Password is required</div>
                        }
                    </div>

                    <div className="error">{this.state.errors.credentials}</div>


                    <div className="form-group mt-3">
                        <button className="btn btn-primary">Login</button>
                    </div>

                </form>
            </div>
        );
    }
}
4 Answers

React hooks aren't compatible with class-components, they can only be used by function components and custom React hooks, so you will need to access the history object another way.

  1. If Login component is directly rendered by a Route component, i.e. <Route path="......" component={Login} /> then route props are already injected as props. You can safely access this.props.history and issue the imperative navigation.

    handleSubmit(e) {
      e.preventDefault();
    
      this.setState({ submitted: true });
      const { username, password } = this.state;
      const { dispatch, history } = this.props; // <-- destructure
      const errors = {};
    
      if (username == "admin" && password == "admin") {
        history.push('/dashboard'); // <-- navigate
      } else {
        errors["credentials"] = "You have entered the wrong username or password.";
        this.setState({ errors }); // <-- move error state update here
      }
    }
    
  2. Use the withRouter Higher Order Component to inject the route props, then access the history object as above.

    import { withRouter } from 'react-router-dom';
    
    ...
    
    export default withRouter(Login);
    

    Don't forget to update and default import Login here it's rendered.

You can't use hooks in a Class Component, it can only be used in just functional Components. that's why you are getting this error.

you can redirect in Class Components by using

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

<Redirect to="/dashboard" />

You cannot use hooks like 'useHistory' in class based component, so change your handleSubmit function to something like this:

handleSubmit(e) {
        e.preventDefault();

        //const history = useHistory();
        this.setState({ submitted: true });
        const { username, password } = this.state;
        const { dispatch } = this.props;
        let errors = {};

        if (username == "admin" && password == "admin") {

            props.history.push('/dashboard');
            console.log("Logged-in");

        } else {

            errors["credentials"] = "You have entered the wrong username or password.";

        }

        this.setState({
            errors: errors
        });

    }

You can use props.history.push

when you have used a class component you cant use hook in react so you need to used another thing like if the component that is used inside the route is in the browser route you can this.props.history.push('your location')if not found like that

<Route to="login" component={login}/>

else you can use this shape <Redirect to="/dashboard" />

Related