I am trying to create a parent/overarching context
. The purpose of the context is to store UserInfo
which should then be available to all children.
UserInfo
is set by getting config from an API.
Context.ts:
import type { User } from 'my-lib';
import { Dispatch, SetStateAction } from 'react';
export const UserContextProps = {
setUser?: Dispatch<SetStateAction<User>>,
userConfig?: User
}
export const UserContext = createContext<UserContextProps>({});
UserProvider.tsx
import { UserContext } from './Context'
const UserProvider = ({children}) =>{
const [data, setUser] = useState<User>({});
useEffect(() =>{
fetchData().then(res => setUser(res.data))
},[]);
return(
<UserContext.Provider value={{setUser: setUser, userConfig: data}}>
{Object.keys(user).length > 0 ? (
<>{children}</>
) : (
<div>Loading</div>
)}
</UserContext.Provider>
)
}
Our app is made up of many small sites like cart.html
, description.html
, profile.html
each of these has its own component. I am trying to wrap each of these with UserProvider
so the children:
1. Render after userConfig is set
2. Have access to userConfig
Cart.tsx
import { UserProvider } from 'UserProvider';
import React, { useContext } from 'react';
import { UserContext } from './Context'
export const UserCartApp = () => {
const { userConfig } = useContext(UserContext);
return (
<UserProvider>
<Header userConfig={userConfig} />
<SelectedProducts userConfig={userConfig} />
<SubTotal userConfig={userConfig} />
<Footer />
</UserProvider>
)
}
Inside i have:
Header.tsx
export const Header = ({userConfig}) => {
console.log('header config', userConfig);
....
....
The above console.log
of userConfig is always {}
2
Answers
You are using
UserContext
inUserCartApp
which is not wrapped byUserProvider
. Instead of that use it inHeader
like this.Issue
Components not wrapped in the Context provider will receive the default value.
The
UserContext
has a default value of{}
.Since
UserCartApp
is the component rendering theUserProvider
component providing theUserContext
it can’t itself access the provided value.Solution
Lift the
UserProvider
component higher in the ReactTree such that it can provide theUserContext
value toUserCartApp
.Example:
Improvement/Suggestion
One of the problems the React Context API solves for though is props drilling. It doesn’t make sense to access the context value in the parent component and then pass it down as props to each child component. An improvement here would be to simply have each child use the
const { userConfig } = useContext(UserContext);
.Example: