react: 16.6 Context API not working in class component
Do you want to request a feature or report a bug? Quite possibly a bug (or maybe confusion about the current API)
I am using the new Context API as well as the new static contextType in React 16.6. I am passing context down a couple components deep but when I attempt to access the context within the component, the object is empty (~only the default value passed into createContext is being displayed~). This is happening in a current feature I am working on at my job, so I cannot display that code, but I did create a Codesandbox with the gist of the problem.
Here is a demonstration of the behavior: https://codesandbox.io/s/r4myz959ro
I would expect to be able to access the current values of the context. This way, if those values change, I would always have the most recent values. Now, maybe this is expected behavior, however, it would be confusing if it is.
React 16.6 ReactDOM 16.6
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 29
- Comments: 37 (2 by maintainers)
@dericgw the problem you’re describing has nothing to do with React, it’s the behavior of circular ES6 module imports. Here’s an example showing the same problem without React.
The index file imports
View, which imports the index file and theAnotherLevelDeep, which itself requires the index file again. It’s a circular dependency.The reason it works with the
Context.ConsumerAPI is that the render method is lazily evaluated, while the class definition (including static properties) are evaluated when the module is loaded.Did u manage to resolve it? I’m facing similar issue.
context is an empty object
{}even if I did something like thisI’m quite sure I have no cyclic rendering, make sure I’m on
16.6.0but nothing seems to work.Can’t get this to work either, enclosing in <.Consumer> works fine, but the static contextType object is always empty. Using latest React Native (with navigation)
@javascrewpt My issue is why do I have to create context in a separate file? Where in the docs does it say this? The example used in the docs has the context created in the same file: https://reactjs.org/docs/context.html#when-to-use-context
When the docs say one thing and the code behaves differently, this is usually one of three things:
I am willing to accept any of the above. While you have provided a workaround, of sorts, it does not address the root cause.
Now, on to your proposed solution. As I have previously stated/questioned, what if my top-level component tracks state and also passes methods to change that state (please see the original codesandbox, which I’ve update: https://codesandbox.io/s/r4myz959ro)? Your simple solution is no longer valid. I would have to completely refactor my solution to separate out the context provider into another top-level component that tracks state, etc. This may be the correct way to do it. But, then again, where is this documented? And, we are back to the original question and the root of the problem.
The documentation makes it seem like my approach should work. It does not mention (anywhere that I can see) why it would not work. Is this a bug, a mistake in documentation, or did I interpret something incorrectly?
I am not trying to dismiss your help and I appreciate you attempting to find a solution for the problem. However, if you are just trying to prove a point by telling me that you, “don’t believe I am using it correctly” or that, “there is no bug and it works as intended”, please do not feel that you need to help anymore.
I’m sorry if I came off too aggressive, I wasn’t trying to dismiss your issue, it’s just my lack of knowledge about this that made me question the problem. And you elaborated perfectly and I understand now your concern. I’m looking forward to hearing from some experts about this, seems an interesting issue.
@javascrewpt While I do believe that is one way to use the Context API, have you looked at this: https://reactjs.org/docs/context.html#classcontexttype ?
By the looks of that, I should be able to do what I am attempting to do.
In this issue, we’ve seen two kinds of problems:
contextTypeto beundefinedor empty object instead of the context. (This can happen in legacy environments that don’t have real ESM with which it would be an error.)We added a better warning for the circular dependency case in https://github.com/facebook/react/pull/15142 which will be included in next release. That should make the first case much easier to diagnose.
For doc problems, I filed https://github.com/reactjs/reactjs.org/issues/1842 to track them. The second problem will also gradually go away as more people update React.
I don’t think there’s anything else actionable in this issue so I’m closing. Thanks everyone for feedback.
For my case, I forgot to upgrade
react-domto 16.6.0, I manage to get it working after upgrade!@clintjansen I think you might need react-native to official support 16.6.0
This is not currently working in Expo (version v32.0.0). See https://snack.expo.io/@badbod99/calm-candies. Code based on React Context example, updated for React Native.
Setting contextType as ‘ThemedButton.contextType = ThemeContext;’ does not result in this.context having current context value from ThemeContext.Provider above.
Using ‘<ThemeContext.Consumer>’ does work.
Not a circular reference issue nor a documentation problem. Context creation is in separate file.
@javascrewpt That is a solution, but the approach seems to avoid the original issue. Also, the top-level component could be used to store state and also provide methods that manipulate that state. In your last example, you would need to jump through more hoops to account for that. From what I can tell, this is the whole purpose of the changes to the context API in 16.6:
Quoted from: https://reactjs.org/blog/2018/10/23/react-v-16-6.html?no-cache=1#static-contexttype
I appreciate your help. I would like to address the root of the issue or gain clarification of the intentions of the API. If the API is not supposed to work like I am attempting to use it, then I would propose (and even help) in clarifying the documentation so that others do not run into the same issue.
I had the exact same problem, running react native & using react-navigation.
As an observation having independent files or not changed nothing in all my tests.
What fixed it for me, using react-navigation was to have my ContextProvider as the highest level of the application:
I had same problem, but I used react 16.6.0 and react-dom 16.5.0 😃 With react 16.6.0 and react-dom 16.6.0 it works as expected.
IMO we should warn if it looks like a circular dependency (empty object or
undefined).I ran into the same issue as @dericgw, and came to the same conclusion as https://github.com/facebook/react/issues/13969#issuecomment-433253469 by @aweary, that it is a circular dependency problem. I had to move the Context creation out into a separate file, that both the parent component (that holds the
Provider), and the child component (that consumes) imports from. this solves the dependency problem for me, at least.I don’t know how common this problem is, but I agree with @dericgw that if you follow the documentation to the point, you run into this problem, which means there should probably be a note about it in the docs. It seems like @sophiebits are in charge of the docs, do you agree with me?
Ah, indeed, indeed. I should’ve checked the changelog. I would’ve noted that the
this.contextsyntax arrived with 16.6. Thanks for pointing me in the right direction.The better warning is included with 16.8.6.
Hi! React Context works perfectly on my application on development environment with Webpacker but when I precompile my assets to serve my application in production environment it throw me
TypeError: undefined is not an object (evaluating 'n.context.user.username')error. I tried implementing all the suggested solutions but it still didn’t work. I upgrade the versions: to"react": "^16.7.0", "react-dom": "^16.6.0"and defining the Context creation in a separate file. The app will work fine if we use<UserContext.Consumer/>but want to stick to try our best to stick to thecontextTypemethod. Would appreciate any help. Thank you.Here are the links for the code:
Context Creation https://github.com/VantageSG/Vantage/blob/master/app/javascript/contexts/UserContext.jsx
Context Provider https://github.com/VantageSG/Vantage/blob/master/app/javascript/components/App.jsx
Context Consumer https://github.com/VantageSG/Vantage/blob/master/app/javascript/components/navBar/desktopNavBar.jsx
moving
createContextcall to a seperate file/module fixed the problem for us.@jacksongabbard it seems like the codesandbox you shared is still using the 16.5.2 versions of React and React-dom and not 16.6.0, here is a codesandbox using 16.6 showing the context being assigned and rendered correctly: https://codesandbox.io/s/m31mv7wox9
Exporting/importing removes circular dependency. This answer explains it perfectly https://stackoverflow.com/questions/56384761/cannot-access-class-contexttype-within-a-child-component
Already reported (and they replied). They’ve not yet updated expo to 16.8, so it doesn’t yet support static contextType. Seems they have been waiting for RN 0.59 before making the next jump. No date as of yet.
@elias551 Have you tried the fix suggested here https://github.com/facebook/react/issues/13969#issuecomment-433253469? I had the same issue and moving the context creation into its own file fixed it for me. So my file structure was like:
I too was bitten by this and once I hoisted the context creation into its own file (i.e., one
Context.jsfile and a separateContextProvider.jsfile), everything worked. It also obviated the need for wrapping some components with<Context.Consumer>asthis.contextis now readily available to the component’s render method.But I think the real issue here is the documentation (as noted above). Currently, it reads almost as a stream of consciousness, meandering between what not to do and ending up with potential pitfalls. There is a lack of prescriptive information that outlines clear use-cases and patterns to the developer.
Agreed, this is a new API and patterns are still emerging so I’m afraid we’ll be dealing with a depth-first tree-traversal of incorrect application models until stumbling on the right track as outlined in this thread (and I am very appreciative for the smart comments posted here that made my stuff work).