I am currently learning React and stuck on context API, basically I am trying to use State inside context to check whether or not a user is logged in or not using a simple boolean isAuthenticated State. Trouble is, While context is visible to both the components, any change made to said State are not getting reflected into other component as it should when using context.
here is my code,
AuthContext.js
import React, { createContext, useState } from 'react';
export const AuthContext = createContext();
export const AuthContextProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
console.log("AuthCOntext", AuthContext);
const contextValue = {
isAuthenticated,
// updateIsAuthenticated,
setIsAuthenticated
};
return (
<AuthContext.Provider value={contextValue}>
{children}
</AuthContext.Provider>
);
};
LoginForm.js
import React, { useContext, useEffect, useState } from 'react';
import Button from 'react-bootstrap/Button';
import formStyles from '../../styles/form.module.css';
import { postLoginForm } from '../../helpers/RequestHelper';
import { AuthContext } from '../../contexts/AuthContext';
export default function LoginForm() {
const { isAuthenticated, setIsAuthenticated } = useContext(AuthContext);
const [returnedResponseState, setReturnedResponseState] = useState({
status: 0,
text: ''
})
async function submitLoginForm(event) {
event.preventDefault();
const form = event.target;
const formData = new FormData(form);
const actualFormData = Object.fromEntries(formData.entries());
console.log(actualFormData);
console.log("Before updateIsAuthenticated:", isAuthenticated);
await postLoginForm(actualFormData).then(
(res) => {
console.log(res);
if (!res) {
}
else {
setReturnedResponseState({ status: res.status, text: res.data }, () => {
console.log(returnedResponseState);
});
if (res.status === 200) {
setIsAuthenticated(true);
}
}
});
console.log("after updateIsAuthenticated", isAuthenticated);
}
return (
<div className={formStyles.formDiv} id='loginform'>
{console.log(isAuthenticated)}
<form onSubmit={submitLoginForm}>
<h5>Login</h5>
<div>
{returnedResponseState ? returnedResponseState.text : null}
</div>
<div className={formStyles.formElement}>
<label htmlFor="emailID" className={formStyles.formElementLabel}>Email ID</label>
<input type='email' name="emailID" placeholder="[email protected]"></input>
</div>
<div className={formStyles.formElement}>
<label htmlFor="Password1" className={formStyles.formElementLabel}>Password</label>
<input type="password" name="password1" placeholder="*****"></input>
</div>
<Button type='submit'> Log in</Button>
</form>
</div>
)
}
Library.js
import React, { useState, useEffect, useContext } from 'react';
import Card from 'react-bootstrap/Card';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import { AuthContext } from '../../contexts/AuthContext';
import { getUserData } from '../../helpers/RequestHelper';
export default function Library() {
const { isAuthenticated } = useContext(AuthContext);
const [response, setResponse] = useState(null);
useEffect(() => {
async function getUserPageData() {
const result = await getUserData();
setResponse(result.playlist);
console.log("Is authenticated", isAuthenticated);
}
getUserPageData();
}, []); // Add isAuthenticated as a dependency
return (
<div>
<div>
<h5>Your Playlists</h5>
<h6>playlist name</h6>
<Row xs={1} md={2} lg={3} xl={3}>
{response && response.length !== 0 ? (
response.map((video) => (
<Col>
<Card>
<p>{video.title}</p>
</Card>
</Col>
))
) : (
<p>You currently have no playlists created</p>
)}
</Row>
</div>
</div>
);
}
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { AuthContextProvider } from './contexts/AuthContext';
import { Children } from 'react';
const root = ReactDOM.createRoot(document.getElementById('root'));
console.log(root);
root.render(
<React.StrictMode>
<AuthContextProvider value={Children}>
<App />
</AuthContextProvider>
</React.StrictMode>
);
reportWebVitals();
App.js
import './App.css';
import {
createBrowserRouter,
Outlet,
RouterProvider,
} from 'react-router-dom';
import Index from './components/Index';
import NavigationBar from './components/Navbar/NavigationBar';
import VideoPlayerPage from './views/VideoPlayerPage'
import AccountPage from './views/AccountPage';
import LoginSignupPage from './views/LoginSignupPage';
import Library from './components/Account/Library';
import UploadVideoForm from './components/Forms/UploadVideoForm';
const router = createBrowserRouter([
{
path: "/",
element: <Index />
},
{
path: "/watch/:videoId",
element: <VideoPlayerPage />
},
{
path: "/login",
element: <LoginSignupPage />
},
{
path: "/user/home",
element: <AccountPage />
},
{
path: "/library",
element: <Library />
},
{
path: "/upload",
element: <UploadVideoForm />
}
])
function App() {
return (
<>
<NavigationBar />
<RouterProvider router={router}>
<Outlet />
</RouterProvider>
</>
);
}
export default App;
I might be wrong here, but I have tried wrapping context function is useEffect hook to trigger a re-render of any component that might be using the AuthContext, so far I am unable to find answer as everything seems right to me and both react and developer console do not raise any error execpt a warning "State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect()."
You are deconstructing it wrongly. In the library do this, which means, from the array returned assign the first element to the isAuthenticated variable (use brackets []
)
const [isAuthenticated] = useContext(AuthContext);
In the code you shared in the question you did this with curly braces {}
which means, get the property isAuthenticated from the return, as its an array it always returns undefined
const { isAuthenticated } = useContext(AuthContext);
In the codesandbox you did this, which means assign everything to isAuthenticated, which is always an array
const isAuthenticated = useContext(AuthContext);
Also if you are navigating without the router, typing the URL or hitting F5 for example, all states will be reset I just updated your code to navigate using the router Link:
https://codesandbox.io/s/focused-shannon-3k667f?file=/src/LoginPage.js