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