Reputation: 1674
I am using React Context api to pass some states to different child components and it's returning undefined
.
Parent component:
export const UserContext = React.createContext();
export class Provider extends Component {
state = {
editGroup: false,
}
render() {
return (
<UserContext.Provider value={{
state: this.state
}}>
{this.props.children}
</UserContext.Provider>
)
}
}
Child component:
import { UserContext } from './index';
return (
<React.Fragment>
<UserContext.Consumer>
{(context) => (
<p>im inside the consumer {console.log(context)}</p>
)}
</UserContext.Consumer>
</React.Fragment>
);
This last console.log
is returning as undefined
, what am I doing wrong here ?
Upvotes: 22
Views: 51394
Reputation: 156
I was facing same issue except that it was a functional component with useContext Hook instead of <ContextProvider.Consumer/>
component. I realized that I was using the context in the immediate descendant component of the ancestor component having states to pass and the point is that we dont need context in the immediate descent because there we already have the props and if we use context React will surely throw errors.
You can further read the Bug here. It will surely help you if your reason of gettig undefined is same as in the discussion here:
https://github.com/facebook/react/issues/18629#issuecomment-1080852523
Also it helps in the problem where you are getting state value in the context of only the default one not the modified one
Upvotes: -1
Reputation: 99
You need to provide a context default value in createContext()
Like
export const UserContext = React.createContext('default');
Or
export const UserContext = React.createContext({ctx_key:"ctx_value"});
Upvotes: 4
Reputation: 864
I ran into this issue myself recently. In my case, I was calling <MyContext.Consumer>{(context) => /* ... */}</MyContext.Consumer>
from within a portal that was outside of my provider. Composition matters here!
<MyContext.Provider>
/* ... tons and tons of code */
<MyContext.Consumer>
{(context) => {
return (
<Modal foo={context.foo} /> // gets rendered in a portal, far below the provider, but we've made a closure over it, so it's OK
)
}}
</MyContext.Consumer>
</MyContext.Provider>
Upvotes: 3
Reputation: 15579
Also, make sure to pass context in the constructor if you override it!
export default class Profile extends React.Component {
static contextType = AuthContext;
// make sure you pass the context along to super!
constructor(props, context) {
super(props, context);
...
}
}
Upvotes: 27
Reputation: 3887
In the child component change context to value (function parameter) in the Consumer section as thats is the prop passed to the Provider
<UserContext.Consumer>
{(value) => (
<p>im inside the consumer {console.log(value)}</p>
)}
</UserContext.Consumer>
Full working sample
import React, { Component } from 'react'
const UserContext = React.createContext()
const Main = () => (
<Parent>
<Child/>
</Parent>
)
export default Main
//***************************************/
class Parent extends Component {
state = {
editGroup: false
}
render() {
return (
<UserContext.Provider value={{
state: this.state
}}>
{this.props.children}
</UserContext.Provider>
)
}
}
//***************************************/
const Child = () => {
return (
<React.Fragment>
<UserContext.Consumer>
{(value) => (
<p>Inside consumer {console.log(value)}</p>
)}
</UserContext.Consumer>
</React.Fragment>
);
}
//***************************************/
Output: state: {editGroup: false}
Upvotes: 4