I'm currently in the process of creating a context provider to keep track of a logged in user
When the user logs in, I want to call a hook that uses the "setUser" function to update the "user" in state
I've created a cut-down version of my app in CodePen here
Breakdown:
Step 1
Create the 'UserContext' with a default value
const UserContext = React.createContext( {
user: { name:"Jeoff": id: -1 },
setUser: () => null
});
Step 2
Create the provider wrapper where I pass in the "user", and "setUser"
const UserContextProvider = ({ children }) => {
const [user, setUser] = React.useState();
return (
<UserContext.Provider
value={{
user,
setUser
}}
>
{children}
</UserContext.Provider>
)
}
Step 3
Create the hook. The hook returns a higher-order function that is called later, and deconstructs the 'UserContext'
function useLoginUser() {
const { setUser } = React.useContext(UserContext); // This is causes the error
async function loginUser(user) {
setUser(user);
}
return loginUser;
}
Step 4
Implement the 'loginUser' function, and call it
const App = () => {
const loginUser = useLoginUser;
const onSubmit = () => {
try {
loginUser({name:"Text", id: 1});
} catch(e){
console.log(e);
}
}
return (
<UserContextProvider>
<div className="container">
<h1>Please help me (:</h1>
<button onClick={onSubmit}>Login</button>
</div>
</UserContextProvider>
)
}
As mentioned, the error comes in Step 3 when we try and deconstruct the 'UserContext'. The error in CodePen wasn't being much use, and it wasn't in my local environment either, to be honest. The error was coming out as 'undefined'
After quite a lot of Googling, it appears people tend to have this issue when they're using their 'Context' outside the scope of the 'Provider', but I don't believe that's the issue here
CodePudding user response:
The problem with your code is the consumer. You did not wrap the Consumer properly with the Provider. Here is your solution:
Step 1 - Create a context:
const UserContext = React.createContext( {
user: { name:"Jeoff", id: -1 },
setUser: () => {}
});
Step 2 - Create a context provider:
const UserContextProvider = ({ children }) => {
const [user, setUser] = React.useState({ name:"Jeoff", id: -1 });
return (
<UserContext.Provider
value={{
user,
setUser
}}
>
{children}
</UserContext.Provider>
)
};
Step 3 - Create a context consumer:
const ReactContextConsumer = () => {
const { user, setUser } = React.useContext(UserContext);
const onSubmit = () => {
try {
setUser({name:"Text", id: 1});
} catch(e){
console.log(e);
}
};
return (
<div className="container">
<h1>Please help me (:</h1>
<button onClick={onSubmit}>Login</button>
{user.name user.id}
</div>
)
};
Step 5 - Use the consumer inside the context provider:
const App = () => {
return (
<UserContextProvider>
<ReactContextConsumer/>
</UserContextProvider>
)
};