I have a Context & Provider that fetches user details, adds them to an object, and stores it in both a state variable and sessionStorage
.
My goal is to provide this data to any widget that needs it without having to send it down via props.
I’ve tried to create a method whereby the userData can be fetched on demand simply by accessing userData
– the API call is made automatically when/if necessary.
UserDataProvider.jsx:
import React, { useState, useContext, createContext } from "react";
import axios from 'axios'
const UserContext = createContext({})
export const theUser = () => useContext(UserContext)
const default_info = {
name: null,
age: null,
hobbies: [],
}
export const UserDataProvider = ( { children } ) => {
const [ userData, setUserData ] = useState(getUserData())
//gets user state from session storage OR a set of defaults OR from the server
async function getUserData(){
var data = JSON.parse(sessionStorage.getItem("userData"))
if (data == "undefined" || data == null){
console.log("no data in session - fetching from server")
data = await FetchUserData()
return data
}
console.log("Found data")
console.table(data)
return data
}
async function FetchUserData(){
var body_json = {"getinfo": 1}
try{
await axios.post('/api/user_info', {
headers: {
'Content-type':'application/json',
'Accept':'application/json',
withCredentials: true
},
body: JSON.stringify(body_json)
}).then((response) => {
if (response.statusText == "OK"){
var userDataObject = {
name: response.data['name'],
age: response.data['savings'],
hobbies: response.data['hobbies'],
}
setUserData(userDataObject)
sessionStorage.setItem('userData', JSON.stringify(userDataObject))
return userDataObject
}
else return null
});
} catch(error){
console.error(error)
return null
}
}
const accessibleObjects = {
userData
}
return (
<UserContext.Provider value={accessibleObjects}>
{ children }
</UserContext.Provider>
)
}
I have also wrapped components in the app…
main.jsx:
import { UserDataProvider } from './context/UserDataProvider.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<AuthProvider>
<UserDataProvider>
<Router >
<App />
</Router>
</UserDataProvider>
</AuthProvider>
</React.StrictMode>,
)
I can see the data being found in the console.
[vite] connecting...
client:614 [vite] connected.
UserDataProvider.jsx:36 Found data
UserDataProvider.jsx:37
(index) Value
name dave
age 35
hobbies {…} {…} {…} {…} {…} {…} {…}
Object
...
However, it never gets used!
For example, the following widget will cause the data to be loaded (I can see it happen in the console), but when I access userData.name, nothing is there.
I get
Username is
in the body.
import { theUser } from '../context/UserProvider.jsx'
const ExampleComponent = () => {
const { userData } = theUser()
return(
<>
<h1>Username is {userData.name}</h1>
</>
)
}
export default ExampleComponent
I’m sure I’m missing something crucial – I fight with this a lot.
Can someone help me understand the intended way to manage data like this?