Search code examples
reactjsreact-reduxreact-hooksredux-thunk

Getting Invalid hook call error on importing a component in React


I have built a login page where on filling the username and password and hitting the submit button, it dispatches the action which basically goes to the backend and checks whether the username and password is valid. I am using React and redux and this is my login page below

login.js (simplified)

import LoginHandle from '../login/LoginHandle'

function userLogin(event) {
  event.preventDefault()
  const username = document.getElementById("username").value
  const password = document.getElementById("password").value
  
  LoginHandle(username, password)

}

const Login = () => {
  return (
    <div className="flex-row align-items-center">
                  <form onSubmit={(e) => userLogin(e)}>
                    <h1>Login</h1>
                    
                      <input id="username" type="email" placeholder="Username" required/>
                 
                      <input id="password" type="password" placeholder="Password" required/>
      
                        <button type="submit" className="px-4">Login</button>
                </form>
    </div>
  )
}

export default Login

LoginHandle.js (simplified)

import {useDispatch, useSelector} from 'react-redux'
import {getLoginStatus} from '../actions/loginAction'


const LoginHandle = (username, password) => {

    const dispatch = useDispatch()
    dispatch(getLoginStatus(username, password))
    const loginState = useSelector(state=> state.loginStatus) 

    if(loginState.loading) {
        console.log("please wait")
    }

    // .... rest of the logic
}

export default LoginHandle

As you can see I try to dispatch the action and then check the state to get confirmation from the backend. But I get this error

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:...

What am I doing wrong?


Solution

  • import {useDispatch, useSelector} from 'react-redux'
    import {getLoginStatus} from '../actions/loginAction'
    
    const useLoginHandler = (username, password, submitted) => {
         const dispatch = useDispatch();
         const loginState = useSelector(state=> state.loginStatus)
         // it is better to put the dispatch inside a useEffect rather than outside
         useEffect(() => {
            if(!submitted) {return};
            dispatch(getLoginStatus(username, password))
         }, [username, password, submitted]);
    
    
        if(loginState.loading) {
            console.log("please wait")
        }
    
        // .... rest of the logic
    }
    
    export default useLoginHandler
    

    And your usage of the hook is wrong. it should not be inside a callback function. it should be at the top level. Something like below. Also you should not access dom elements directly, instead use useRef or useState to get value

    const Login = () => {
       const [username, setUsername] = useState('');
       const [password, setPassword] = useState('')
       const [submitted, setSubmitted] = useState(false);
       useLoginHandler(username, password, submitted); //custom hook should be used at this level
       return (
          <form onSubmit={(e) => setSubmitted(true)}>
          <input id="username" type="email" placeholder="Username" required onChange={e => setUsername(e.target.value)}/>
              </form>   
       )
    }