Home > Blockchain >  How can I navigate to other component here in reactJS
How can I navigate to other component here in reactJS

Time:04-11

I'm new on react JS and I'm getting error of invalid hooks call in this code. The error message is:

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

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

And my API is not running due to this error. This HandleLogin function is in a separate file and I'm importing this function into the protected routes.js file My code is:

function HandleLogin() {
    const navigate = useNavigate() // it gives me the error
    return (e, data) => {
            e.preventDefault();
            fetch('http://localhost:8000/token-auth/', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(data)
            })
                .then(res => res.json())
                .then(json => {
                    localStorage.setItem('token', json.token);
                    username = json.user.username
                    if (json.email === '[email protected]')
                        navigate('/admindb')
                    else
                        navigate('/userdb')
                })
                .catch((res) => document.getElementById('text-error').innerHTML = res.error)
        }
}

I googled it and see, that we can't use hooks in callback functions so I put it outside the function returned by the HandleLogin function but it still gives this error.

I'm wondering what I'm doing wrong, and how to fix it.

I'm using HandleLogin here in my routes like this:

<Route exact path="/login" name="Login Page" element={<Login handle_login={HandleLogin} />} />

And this is my Login.js file:

function Login(props) {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  //const [logged_in, setLogged_in] = useState(localStorage.getItem('token') ? true : false);
  return (
    <div className="bg-light min-vh-100 d-flex flex-row align-items-center">
      {/* <div>{props.myname}</div> */}
      <CContainer>
        <CRow className="justify-content-center">
          <CCol md={8}>
            <CCardGroup>
              <CCard className="p-4">
                <CCardBody>
                  // here I'm calling handle_login 
                  <CForm onSubmit={(e)=>props.handle_login(e,{username,password})}>
                    <h1>Login</h1>
                    <p className="text-medium-emphasis">Sign In to your account</p>
                    <CInputGroup className="mb-3">
                      <CInputGroupText>
                        <CIcon icon={cilUser} />
                      </CInputGroupText>
                      <CFormInput id="username" type="text" placeholder="Username" autoComplete="username"
                          value={username} onChange={e => setUsername(e.target.value)} required />
                    </CInputGroup>
                    <CInputGroup className="mb-4">
                      <CInputGroupText>
                        <CIcon icon={cilLockLocked} />
                      </CInputGroupText>
                      <CFormInput
                        id="password"
                        type="password"
                        placeholder="Password"
                        autoComplete="current-password"
                        value={password}
                        onChange={e => setPassword(e.target.value)}
                        required
                      />
                    </CInputGroup>
                    <CRow>
                      <CCol xs={6}>
                        <CButton type="submit" color="primary" className="px-4">
                          Login
                        </CButton>
                      </CCol>
                      <CCol xs={6} className="text-right">
                        <Link to="/verifyEmail" color="link" className="px-0">
                          Forgot password?
                        </Link>
                      </CCol>
                    </CRow>
                    <CFormFeedback className='text-danger' id='text-error'></CFormFeedback>
                  </CForm>
                </CCardBody>
              </CCard>
              <CCard className="text-white bg-primary py-5" style={{ width: '44%' }}>
                <CCardBody className="text-center">
                  <div>
                    <h2>Sign up</h2>
                    <p>
                      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
                      tempor incididunt ut labore et dolore magna aliqua.
                    </p>
                    <Link to="/register">
                      <CButton color="primary" className="mt-3" active tabIndex={-1}>
                        Register Now!
                      </CButton>
                    </Link>
                  </div>
                </CCardBody>
              </CCard>
            </CCardGroup>
          </CCol>
        </CRow>
      </CContainer>
    </div>
  )
}

My App.js file:

import React, { useEffect } from 'react'
import { HashRouter, Navigate, Outlet, Route, Routes, useNavigate } from 'react-router-dom'
import Home from './views/Pages/Home'
import './scss/style.scss'
// import Register from './views/Pages/Register'
import VerifyEmail from './views/Pages/VerifyEmail'
import ValidateCode from './views/Pages/ValidateCode'
import ChangePassword from './views/Pages/ChangePassword'
import AdminDashboard from './views/Pages/AdminDashboard'
import UserDashboard from './views/Pages/UserDashboard/UserDashboard'

const loading = (
  <div className="pt-3 text-center">
    <div className="sk-spinner sk-spinner-pulse"></div>
  </div>
)

// Pages
const Login = React.lazy(() => import('./views/Pages/Login'))
const Register = React.lazy(() => import('./views/Pages/Register'))

let username = ''

const App = ()=> {
  const navigate = useNavigate()

  function handleLogin() {
    return (e, data) => {
      e.preventDefault();
      fetch('http://localhost:8000/token-auth/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then(res => res.json())
        .then(json => {
          localStorage.setItem('token', json.token);
          username = json.user.username
          if (json.email === '[email protected]')
            navigate('/admindb')
          else
            //<Navigate to='/userdb' />
            navigate('/userdb')
        })
        .catch((res) => document.getElementById('text-error').innerHTML = res.error)
    }
  }

  return (
    <HashRouter>
      <React.Suspense fallback={loading}>
        <Routes>
          <Route exact path="/" name="Home Page" element={<Home />} />
          <Route exact path="/login" name="Login Page" element={<Login handle_login={handleLogin} />} />
          <Route exact path="/register" name="Register Page" element={<Register />} />
          <Route exact path="/verifyEmail" name="Email verification Page" element={<VerifyEmail />} />
          <Route exact path="/verifyItsYou" name="Code verification Page" element={<ValidateCode />} />
          <Route exact path="/changePassword" name="Change password Page" element={<ChangePassword />} />
          <Route exact path="/admindb" name="Admin Dashboard Page" element={<AdminDashboard />} />
          <Route exact path="/userdb" name="User dashboard Page" element={<UserDashboard />} />
        </Routes>
      </React.Suspense>
    </HashRouter>

  )
}

export default App

CodePudding user response:

React hooks can only be called from React functions and custom hooks. They cannot be called in callbacks. Move the useNavigate hook call out of the callback and into the main component body rendering the routes. You'll need to also move the handleLogin callback into the parent component so it can access the in-scope navigate function.

Example:

const App = () => {
  const navigate = useNavigate();

  ...

  function handleLogin() {
    return (e, data) => {
      e.preventDefault();
      fetch('http://localhost:8000/token-auth/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
      })
        .then(res => res.json())
        .then(json => {
          localStorage.setItem('token', json.token);
          username = json.user.username;
          navigate(json.email === '[email protected]'
            ? '/admindb'
            : '/userdb'
          );
        })
        .catch((res) => {
          document.getElementById('text-error').innerHTML = res.error;
        });
    }
  }

  return (
    <React.Suspense fallback={loading}>
      <Routes>
        <Route path="/" name="Home Page" element={<Home />} />
        <Route path="/login" name="Login Page" element={<Login handle_login={handleLogin} />} />
        <Route path="/register" name="Register Page" element={<Register />} />
        <Route path="/verifyEmail" name="Email verification Page" element={<VerifyEmail />} />
        <Route path="/verifyItsYou" name="Code verification Page" element={<ValidateCode />} />
        <Route path="/changePassword" name="Change password Page" element={<ChangePassword />} />
        <Route path="/admindb" name="Admin Dashboard Page" element={<AdminDashboard />} />
        <Route path="/userdb" name="User dashboard Page" element={<UserDashboard />} />
    </Routes>
  </React.Suspense>
  );
}

export default App;

Wrap the HashRouter around the App component:

<HashRouter>
  <App />
</HashRouter?
  • Related