Home > Net >  useNavigate() "not a function" in react-router-dom v6.3.0?
useNavigate() "not a function" in react-router-dom v6.3.0?

Time:07-17

i am working with react-router-dom version 6.3.0 and i've encountered an issue where the useNavigate hook is causing an app-breaking error.

i have browsed many posts (and other sites), and i've checked all of the boxes of basic troubleshooting:

  • the hook is inside a functional component
  • the component is inside a route
  • react-router-dom is version 6.3.0 in package.json

i'm at a loss for how to resolve this, so please let me know. the error and code is below.

Error Message

Uncaught TypeError: (0 , react__WEBPACK_IMPORTED_MODULE_0__.useNavigate) is not a function
    at LoginScreen (LoginScreen.js:9:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at beginWork$1 (react-dom.development.js:27426:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
    at renderRootSync (react-dom.development.js:26434:1)
    at recoverFromConcurrentError (react-dom.development.js:25850:1)
    at performConcurrentWorkOnRoot (react-dom.development.js:25750:1)

LoginScreen.js

import { useState, useEffect, useNavigate } from 'react'; //IMPORT USENAVIGATE HOOK
import axios from 'axios';
import { Link } from 'react-router-dom';



export default function LoginScreen() {

    const navigate = useNavigate();               //INITIALIZE USENAVIGATE HOOK

    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [error, setError] = useState('');

    //make sure they can't get to the login page if they're logged in
    useEffect(() => {
        if (localStorage.getItem('authToken')) {
            navigate('/');                          //CALL USENAVIGATE HOOK
        }
    }, [navigate])                          //PUT USENAVIGATE HOOK IN DEPENDENCY ARRAY

    const loginHandler = async (e) => {
        e.preventDefault();

        //set axios header
        const config = {
            header: {"Content-Type":"application/json"}
        }

        try {
            //make axios request to backend and desturcture data
            const { data } = await axios.post('/api/auth/login', { email, password}, config);

            localStorage.setItem("authToken", data.token);
            
            navigate('/');                          //CALL USENAVIGATE HOOK
        } catch (error) {
            setError(error.response.data.error)
            setTimeout(() => {
                setError('');
            }, 5000)
        }
    }

  return (
    <div className = "login">
        <form onSubmit = {loginHandler} className = "login-form">
            <h3 className = 'login-title'>Login</h3>
            
            {/*display error if error */}
            {error && <span className = "error-message">{error}</span>}


            {/* email group*/}
            <div className = 'form-group'>
                <label htmlFor = "email">Email</label>
                <input 
                    type = "text"
                    required
                    id = 'email'
                    placeholder = 'Enter your email address'
                    value = {email}
                    onChange = {(e) => setEmail(e.target.value)}
                />
            </div>

            {/* password group*/}
            <div className = 'form-group'>
                <label htmlFor = "password">Password</label>
                <input 
                    type = "password" /* i can probably use state to set this to text to make it visible*/
                    required
                    id = 'password'
                    placeholder = 'Enter a password'
                    value = {password}
                    onChange = {(e) => setPassword(e.target.value)}
                />
            </div>

            {/* submit*/}
            <button type = 'submit' className = 'btn btn-primary'>Login</button>

            {/*send to register */}
            <span className = 'login-span'>Don't have an account? <Link to = '/register'>Register</Link></span>
        </form>
    </div>
  )
}

App.js


//routes
import PrivateRoutes from './components/routing/PrivateRoutes';

//screens
import PrivateScreen from './components/screens/PrivateScreen';
import LoginScreen from './components/screens/LoginScreen';
import RegisterScreen from './components/screens/RegisterScreen';
import ForgotPasswordScreen from './components/screens/ForgotPasswordScreen';
import ResetPasswordScreen from './components/screens/ResetPasswordScreen';

const App = () => {
  return (
    <Router>
      <div classname = "app">
        <Routes>
          <Route path = '/' element = {localStorage.getItem('authToken') ? <PrivateScreen /> : <Navigate to = "/" />} />
          <Route path = '/login' element = {<LoginScreen />} />
          <Route path = '/register' element = {<RegisterScreen />} />
          <Route path = '/forgotpassword' element = {<ForgotPasswordScreen />} />
          <Route path = '/resetpassword' element = {<ResetPasswordScreen />} />
        </Routes>
      </div>
    </Router>
  )
}

export default App;

edit: added error message

CodePudding user response:

You should import useNavigate from "react-router-dom"

CodePudding user response:

you should import the useNavigate hook from react-router-dom and then use it like this :

import { useNavigate } from "react-router-dom";

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

  const handleClick = () => {
    navigate("/");    
  };

  return <button onClick={handleClick}>Click me</button>
}
  • Related