React Native Environment Info:
System:
OS: macOS 10.14
CPU: x64 Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz
Memory: 31.34 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 8.11.4 - /usr/local/bin/node
Yarn: 1.10.1 - ~/.yarn/bin/yarn
npm: 6.4.1 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 12.0, macOS 10.14, tvOS 12.0, watchOS 5.0
Android SDK:
Build Tools: 23.0.1, 23.0.3, 24.0.3, 25.0.0, 25.0.1, 25.0.2, 25.0.3, 26.0.0, 26.0.1, 26.0.2, 26.0.3, 27.0.0, 27.0.1, 27.0.2, 27.0.3, 28.0.0, 28.0.2, 28.0.3
API Levels: 19, 22, 23, 24, 25, 26, 27, 28
IDEs:
Android Studio: 3.2 AI-181.5540.7.32.5014246
Xcode: 10.0/10A255 - /usr/bin/xcodebuild
npmPackages:
react: 16.6.0 => 16.6.0
react-native: 0.57.4 => 0.57.4
npmGlobalPackages:
react-native-cli: 2.0.1
Context API works on 16.6.0-alpha.8af6728, but the consumers stop updating after upgrading to 16.6.0 or newer. The release notes say to use 16.6.0-alpha.8af6728 at least. Opening this just to make sure it's a known issue and to track this.
On a related note, I was expecting an alpha version with 16.7.0-alpha.0 support to be already available, to be honest. RN is an important react product, we want to play with new features as soon as possible like everyone else. Let me know how we could help.
import React, { Component } from 'react'
import { Platform, StyleSheet, Text, View } from 'react-native'
const MyContext = React.createContext({ count: 0 })
class Provider extends Component {
state = { count: 0 }
componentDidMount() {
this.interval = setInterval(() => {
this.setState(state => ({ count: state.count + 1 }))
}, 1000)
}
componentWillUnmount() {
clearInterval(this.interval)
}
render() {
return (
<MyContext.Provider value={this.state}>
{this.props.children}
</MyContext.Provider>
)
}
}
export default function App() {
return (
<Provider>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<MyContext.Consumer>
{({ count }) => (
<>
<Text>Welcome to React Native!</Text>
<Text>Count: {count}</Text>
</>
)}
</MyContext.Consumer>
</View>
</Provider>
)
}
Did a bit of digging on this before coming across your issue. The problem seems to stem from facebook/react@3b7ee269259c077956af63b2ad34cbd5b6b15d27 in which in DEV the context is proxied through to an inner _context property and thus any checks regarding the context in DEV needs to access the true context through context._context.
Where this comes into play with ReactNative is that during the call to propagateContextChange() the actual context object is being compared (===) to the proxy object, when in reality it should be compared to the ._context property on the proxy object.
// Check if the context matches.
if (
dependency.context === context &&
(dependency.observedBits & changedBits) !== 0
) {
// Match! Schedule an update on this fiber.
context in the above snippet is the true context object, while dependency.context is the proxy object, and thus the equality check fails and no update is scheduled.
The context property on the dependency is set as part of the updateContextConsumer call. In the linked commit above, the original author clearly accounted for this with his change in ReactFiberBeginWork.js. Further this change was propagated over to this repo with change 8325e09e5cd8538fded1b5a1b4fff1854e17eb22(see the specific line here). That all said, that instance of ReactNativeRenderer-dev.js is not the one currently shipped as part of react-native@latest, even though the latest npm version was shipped days after the commit.
I won't pretend to understand the ship process for all of these integrated files, so I'm not sure if maybe a step was missed or if the latest integrate just hasn't reached time to deploy yet, but the schism here between how react handles context and how react-native is now processing it is causing the problem (at least in my case).
It works since 0.57.5+.
Most helpful comment
Did a bit of digging on this before coming across your issue. The problem seems to stem from facebook/react@3b7ee269259c077956af63b2ad34cbd5b6b15d27 in which in DEV the context is proxied through to an inner
_contextproperty and thus any checks regarding the context in DEV needs to access the true context throughcontext._context.Where this comes into play with ReactNative is that during the call to
propagateContextChange()the actual context object is being compared (===) to the proxy object, when in reality it should be compared to the._contextproperty on the proxy object.contextin the above snippet is the true context object, whiledependency.contextis the proxy object, and thus the equality check fails and no update is scheduled.The
contextproperty on thedependencyis set as part of theupdateContextConsumercall. In the linked commit above, the original author clearly accounted for this with his change in ReactFiberBeginWork.js. Further this change was propagated over to this repo with change 8325e09e5cd8538fded1b5a1b4fff1854e17eb22(see the specific line here). That all said, that instance of ReactNativeRenderer-dev.js is not the one currently shipped as part ofreact-native@latest, even though the latest npm version was shipped days after the commit.I won't pretend to understand the ship process for all of these integrated files, so I'm not sure if maybe a step was missed or if the latest integrate just hasn't reached time to deploy yet, but the schism here between how
reacthandles context and howreact-nativeis now processing it is causing the problem (at least in my case).