I'm new to React and I'm trying to create a user state global context using a context provider so that on submission of the login form, the username and role are updated in the global context with the response of a successful request.
The code for my app is as follows:
import {BrowserRouter,Routes,Route} from 'react-router-dom';
//PAGES AND COMPONENTS
import Registration from './components/registration/Registration';
import Home from './components/home/Home';
import Login from './components/login/Login';
//GLOBAL CONTEXTS
import {AuthProvider} from './context/AuthContext'
function App() {
return (
<div className="App">
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path='/' element={<Home/>}></Route>
<Route path='/Register' element={<Registration/>}></Route>
<Route path='/Login' element={<Login/>}></Route>
</Routes>
</AuthProvider>
</BrowserRouter>
</div>
);
}
export default App;
The code for my Provider (AuthContext.js) is the following:
const AuthContext= React.createContext();
const AuthUpdateContext = React.createContext();
export function useAuth(){
return useContext (AuthContext);
}
export function useAuthUpdate(){
return useContext(AuthUpdateContext);
}
export function AuthProvider({children}){
const [authState,setAuthState]=useState({
id:0,
username:"",
role:"user"
});
return(
<AuthContext.Provider value={authState}>
<AuthUpdateContext.Provider value={setAuthState}>
{children}
</AuthUpdateContext.Provider>
</AuthContext.Provider>
)
};
And the code that's throwing the Invalid Hook error is the following:
import {useNavigate} from 'react-router-dom'
import {Formik, Form, Field,ErrorMessage} from 'formik'
import axios from 'axios';
import * as Yup from 'yup';
import './Login.css';
import {useAuth,useAuthUpdate} from '../../context/AuthContext'
function Login() {
const navigate=useNavigate();
const [invalidCredentials,setInvalidCredentials]=useState("");
const setAuthState=useAuthUpdate;
const useAuthState=useAuth();
const onSubmit=(data)=>{
axios
.post('http://localhost:3001/User/Login',data)
.catch((error)=>{
setInvalidCredentials("Invalid Credentials. Please try again.")
})
.then((response)=>{
localStorage.setItem("token",response.data.token);
setAuthState((prev)=>({
...prev,
id:response.data.id,
username:response.data.username,
role:response.data.role
}))
})
.then(()=>{
console.log(useAuthState);
navigate('/');
})
}
const validationSchema=Yup.object().shape({
usernameOrEmail:Yup
.string()
.required('Field must not be blank.'),
password:Yup.string()
.required('Field must not be blank.'),
});
const initialValues ={
usernameOrEmail:"",
password:"",
};
return (
<div className='container'>
<div className='row'>
<h1>Welcome Back!</h1>
</div>
<div className='row'>
<h2>Log-in Here:</h2>
</div>
<Formik onSubmit={onSubmit} validationSchema={validationSchema} initialValues={initialValues}>
<Form>
<div className='row'>
<label>Username/Email</label>
<Field name='usernameOrEmail'></Field>
<ErrorMessage name="usernameOrEmail">
{msg=><div className="errorMsg">{msg}</div>}
</ErrorMessage>
</div>
<div className='row'>
<label>Password</label>
<Field name='password'
type='password'/>
<ErrorMessage name="password">
{msg=><div className="errorMsg">{msg}</div>}
</ErrorMessage>
</div>
<div id="register-btn"className="row">
<button className="btn btn-secondary" type="submit" >Login</button>
</div>
<div className='row'>
<span className='errorMsg'>{invalidCredentials}</span>
</div>
</Form>
</Formik>
</div>
)
}
export default Login
What I find weird is that both useAuthState
and setAuthState
are React Hooks, and I've positioned them in the same way, but when I console.log useAuthState
, it logs it as :
{id:0, username:"", role:"user"}, whereas when I call setAuthState
, it throws me the following error:
Uncaught (in promise) 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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem. at
Object.throwInvalidHookError
(react-dom.development.js:16227:1) atuseContext
(react.development.js:1618:1) atuseAuthUpdate
(AuthContext.js:12:1) at Login.js:25:1