Reputation: 753
I have the following UserContext.js file, which stores the current logged in user into a user object, and also a setter function. In my Profile component, I want to pre-populate my input fields with the current logged in user's information, which I should be getting using useContext hooks.
The app works fine if I navigate to the Profile page normally from the homepage, but when I try to directly access /profile or reload the page while within the Profile page, I am seeing that my context becomes undefined for a split second (as seen by the console.log), before it loads a value. This causes the useEffect() hook and initializeFields() function to fail because the properties are null.
What I want to happen, is to be able to seamlessly load the current logged in user, and also use it globally in other components within the app. Passing the user object from the parent component as props is not feasible because in reality, my app is a few components deep and prop-drilling wouldn't be a very elegant solution.
const UserContext = React.createContext({
user: {},
setUser: (user) => {},
});
In the App.js component:
const App = (props) => {
const [user, setUser] = useState(null);
return (
<div className="app">
<UserContext.Provider value={{ user, setUser }}>
<Switch>
<Route path="/profile" exact component={Profile} />
</Switch>
</UserContext.Provider>
</div>
);
The Profile.js component:
const DashboardProfileModal = (props) => {
const userContext = useContext(UserContext);
const [name, setName] = useState();
const [username, setUsername] = useState();
const [password, setPassword] = useState();
const [address, setAddress] = useState();
console.log(userContext)
useEffect(() => {
initializeFields();
});
const initializeFields = () => {
setName(userContext.user.name);
setUsername(userContext.user.username);
setPassword(userContext.user.password);
setAddress(userContext.user.address);
};
Upvotes: 5
Views: 7663
Reputation: 5455
You could do something like below and make sure that userContext is available before attempting to use it.
You should also at least make the useEffect
run once on page load by adding the []
(else it will fire constantly on every render). I've also added userContext
as a dependency to the useEffect
and then I check userContext
and name
. This means it will ensure userContext
is not null
before it attempts to run your method.
Then I also include the !name
check so that we can ensure it doesn't keep attempting to run your method once your state has been set for the first time.
const DashboardProfileModal = (props) => {
const userContext = useContext(UserContext);
const [name, setName] = useState();
const [username, setUsername] = useState();
const [password, setPassword] = useState();
const [address, setAddress] = useState();
console.log(userContext)
useEffect(() => {
if(userContext && !name){
initializeFields();
}
},[userContext]);
const initializeFields = () => {
setName(userContext.user.name);
setUsername(userContext.user.username);
setPassword(userContext.user.password);
setAddress(userContext.user.address);
};
Upvotes: 4
Reputation: 3243
I believe the problem you're facing is because you have the provider declared on the App
component. If you want it to be globally accessible to the whole application you should have it on your index.js
file, wrapping the App
component. Something like:
ReactDOM.render(
<React.StrictMode>
<UserContext.Provider>
<App />
</UserContext.Provider>
</React.StrictMode>,
document.getElementById("root")
)
Upvotes: -2