I am unable to set context state in my app.js, I get empty values in it somehow, but can access it in child ponent.
I want to set context state in app.js whenever user es to page so that I can use it throughout the application, for example show different headers based on whether user is logged in or not
SandBox URL as requested -> =/src/App.js
I am following
app.js
// import installed dependencies
import React, { useEffect, useContext } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
// import custom contexts
import { AuthContext, AuthContextProvider } from './contexts/auth/AuthContext';
// import pages
import Homepage from './pages/homepage/Homepage';
// import ponents
import Footer from './ponents/footer/Footer';
import Header from './ponents/header/Header';
export default function App() {
const [authState, setAuthState] = useContext(AuthContext);
useEffect(() => {
console.log(authState); // prints *{}*
console.log(setAuthState); // prints *() => {}*
const token = localStorage.getItem('token');
const tokenIsExpired = parseInt(localStorage.getItem('tokenIsExpired'));
if (!tokenIsExpired && token.length) {
setAuthState({
userIsLoggedin: true,
fName: 'test fname',
lName: 'test lname',
userName: 'testname'
});
} else {
setAuthState({
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
});
}
if (tokenIsExpired) {
localStorage.setItem('token', '');
}
}, [authState, setAuthState]);
return (
<Router>
<AuthContextProvider value={[authState, setAuthState]}>
<div className='App'>
<Header />
<Switch>
<Route exact path='/'>
<Homepage />
</Route>
</Switch>
<Footer />
</div>
</AuthContextProvider>
</Router>
);
}
AuthContext.js
import React, { useState, createContext } from 'react';
const AuthContext = createContext([{}, () => {}]);
const AuthContextProvider = (props) => {
const [authState, setAuthState] = useState({
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
});
return (
<AuthContext.Provider value={[authState, setAuthState]}>
{props.children}
</AuthContext.Provider>
);
};
export { AuthContext, AuthContextProvider };
UseAuthCOntext.js
import { useContext } from 'react';
import { AuthContext } from './AuthContext';
const useAuthContext = () => {
const [authState, setAuthState] = useContext(AuthContext);
const login = (loginDetails) => {
setAuthState({
userIsLoggedin: true,
fName: 'test fname',
lName: 'test lname',
userName: 'testname'
});
};
const logout = () => {
setAuthState({
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
});
};
return { login, logout };
};
export default useAuthContext;
Header.js
// import installed dependencies
import React, { useContext, useEffect } from 'react';
// import ponents
import LoggedOutHeader from './logged-out-header/LoggedOutHeader';
import LoggedInHeader from './logged-in-header/LoggedInHeader';
// import custom contexts
import { AuthContext } from '../../contexts/auth/AuthContext';
const Header = () => {
const [authState, setAuthState] = useContext(AuthContext);
console.log(authState); //prints *{userIsLoggedin: false, fName: "", lName: "", userName: ""}*
console.log(setAuthState); //prints *ƒ dispatchAction(fiber, queue, action) {...*
const header = authState.isUserLoggedIn ? (
<LoggedInHeader />
) : (
<LoggedOutHeader />
);
return header;
};
export default Header;
I am unable to set context state in my app.js, I get empty values in it somehow, but can access it in child ponent.
I want to set context state in app.js whenever user es to page so that I can use it throughout the application, for example show different headers based on whether user is logged in or not
SandBox URL as requested -> https://codesandbox.io/s/quizzical-snyder-2qghj?file=/src/App.js
I am following https://upmostly./tutorials/how-to-use-the-usecontext-hook-in-react
app.js
// import installed dependencies
import React, { useEffect, useContext } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
// import custom contexts
import { AuthContext, AuthContextProvider } from './contexts/auth/AuthContext';
// import pages
import Homepage from './pages/homepage/Homepage';
// import ponents
import Footer from './ponents/footer/Footer';
import Header from './ponents/header/Header';
export default function App() {
const [authState, setAuthState] = useContext(AuthContext);
useEffect(() => {
console.log(authState); // prints *{}*
console.log(setAuthState); // prints *() => {}*
const token = localStorage.getItem('token');
const tokenIsExpired = parseInt(localStorage.getItem('tokenIsExpired'));
if (!tokenIsExpired && token.length) {
setAuthState({
userIsLoggedin: true,
fName: 'test fname',
lName: 'test lname',
userName: 'testname'
});
} else {
setAuthState({
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
});
}
if (tokenIsExpired) {
localStorage.setItem('token', '');
}
}, [authState, setAuthState]);
return (
<Router>
<AuthContextProvider value={[authState, setAuthState]}>
<div className='App'>
<Header />
<Switch>
<Route exact path='/'>
<Homepage />
</Route>
</Switch>
<Footer />
</div>
</AuthContextProvider>
</Router>
);
}
AuthContext.js
import React, { useState, createContext } from 'react';
const AuthContext = createContext([{}, () => {}]);
const AuthContextProvider = (props) => {
const [authState, setAuthState] = useState({
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
});
return (
<AuthContext.Provider value={[authState, setAuthState]}>
{props.children}
</AuthContext.Provider>
);
};
export { AuthContext, AuthContextProvider };
UseAuthCOntext.js
import { useContext } from 'react';
import { AuthContext } from './AuthContext';
const useAuthContext = () => {
const [authState, setAuthState] = useContext(AuthContext);
const login = (loginDetails) => {
setAuthState({
userIsLoggedin: true,
fName: 'test fname',
lName: 'test lname',
userName: 'testname'
});
};
const logout = () => {
setAuthState({
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
});
};
return { login, logout };
};
export default useAuthContext;
Header.js
// import installed dependencies
import React, { useContext, useEffect } from 'react';
// import ponents
import LoggedOutHeader from './logged-out-header/LoggedOutHeader';
import LoggedInHeader from './logged-in-header/LoggedInHeader';
// import custom contexts
import { AuthContext } from '../../contexts/auth/AuthContext';
const Header = () => {
const [authState, setAuthState] = useContext(AuthContext);
console.log(authState); //prints *{userIsLoggedin: false, fName: "", lName: "", userName: ""}*
console.log(setAuthState); //prints *ƒ dispatchAction(fiber, queue, action) {...*
const header = authState.isUserLoggedIn ? (
<LoggedInHeader />
) : (
<LoggedOutHeader />
);
return header;
};
export default Header;
Share
Improve this question
edited Jun 30, 2020 at 8:21
Abhishek Dhanraj Shahdeo
asked Jun 30, 2020 at 6:59
Abhishek Dhanraj ShahdeoAbhishek Dhanraj Shahdeo
1,3562 gold badges14 silver badges35 bronze badges
2
- Rule 101 never add the setter function in the dependency array of useeffect – vinayak shahdeo Commented Jun 30, 2020 at 7:11
- Please create a sandbox and share – vinayak shahdeo Commented Jun 30, 2020 at 7:14
3 Answers
Reset to default 8You could use the context provider inside index.js
.
ReactDOM.render(
<AuthContextProvider>
<App />
</AuthContextProvider>,
document.getElementById('root')
)
Your are using the context in the App ponent, which is not wrapped within AuthContextProvider. In that case the useContext call in the App ponent will not return the value provided to AuthContextProvider but instead it'll return the "default" values provided to the createContext call.
You need to defer those logic in the App ponent to a children ponent within AuthContextProvider.
See note from createContext api: The defaultValue argument is only used when a ponent does not have a matching Provider above it in the tree. This can be helpful for testing ponents in isolation without wrapping them. Note: passing undefined as a Provider value does not cause consuming ponents to use defaultValue.
You are passing value
to AuthContextProvider
, which seems like the value
you want to use, and you don't use it.
// value not used inside `AuthContextProvider`
<AuthContextProvider value={[authState, setAuthState]}>
It should be:
const AuthContextProvider = (props) => {
return (
<AuthContext.Provider value={props.value}>
{props.children}
</AuthContext.Provider>
);
};