Skip to content

Commit

Permalink
Support React.Context, impliments #979
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey committed May 16, 2018
1 parent acea0de commit 56fdd05
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
12 changes: 12 additions & 0 deletions src/internal/reactUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,15 @@ export const updateInstance = instance => {

export const isFragmentNode = ({ type }) =>
React.Fragment && type === React.Fragment

const ContextType = React.createContext ? React.createContext() : null
const ConsumerType = ContextType && ContextType.Consumer.$$typeof
const ProviderType = ContextType && ContextType.Provider.$$typeof

export const CONTEXT_CURRENT_VALUE = '_currentValue'

export const isContextConsumer = ({ type }) =>
type && typeof type === 'object' && type.$$typeof === ConsumerType
export const isContextProvider = ({ type }) =>
type && typeof type === 'object' && type.$$typeof === ProviderType
export const getContextProvider = type => type && type._context
34 changes: 30 additions & 4 deletions src/reconciler/hotReplacementRender.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import {
updateInstance,
getComponentDisplayName,
isFragmentNode,
isContextConsumer,
isContextProvider,
getContextProvider,
CONTEXT_CURRENT_VALUE,
} from '../internal/reactUtils'
import reactHotLoader from '../reactHotLoader'
import logger from '../logger'
Expand All @@ -22,7 +26,9 @@ const stackReport = () => {
logger.warn('in', rev[0].name, rev)
}

const REACT_CONTEXT_CURRENT_VALUE = '_currentValue'
const emptyMap = new Map()
const stackContext = () =>
(renderStack[renderStack.length - 1] || {}).context || emptyMap

const areNamesEqual = (a, b) =>
a === b || (UNDEFINED_NAMES[a] && UNDEFINED_NAMES[b])
Expand Down Expand Up @@ -253,10 +259,12 @@ const scheduleInstanceUpdate = instance => {
const hotReplacementRender = (instance, stack) => {
if (isReactClass(instance)) {
const type = getElementType(stack)

renderStack.push({
name: getComponentDisplayName(type),
type,
props: stack.instance.props,
context: stackContext(),
})
}
const flow = transformFlowNode(filterNullArray(asArray(render(instance))))
Expand Down Expand Up @@ -312,18 +320,35 @@ const hotReplacementRender = (instance, stack) => {
return
}

// React context consumer
if (child.type && typeof child.type === 'object' && child.type.Consumer) {
// React context
if (isContextConsumer(child)) {
try {
next({
children: (child.props ? child.props.children : child.children[0])(
child.type[REACT_CONTEXT_CURRENT_VALUE],
stackContext().get(child.type) || child.type[CONTEXT_CURRENT_VALUE],
),
})
} catch (e) {
// do nothing, yet
}
} else if (typeof child.type !== 'function') {
// React
let childName = child.type ? getComponentDisplayName(child.type) : 'empty'
let extraContext = stackContext()

if (isContextProvider(child)) {
extraContext = new Map(extraContext)
extraContext.set(getContextProvider(child.type), child.props.value)
childName = 'ContextProvider'
}

renderStack.push({
name: childName,
type: child.type,
props: stack.instance.props,
context: extraContext,
})

next(
// move types from render to the instances of hydrated tree
mergeInject(
Expand All @@ -334,6 +359,7 @@ const hotReplacementRender = (instance, stack) => {
stackChild.instance,
),
)
renderStack.pop()
} else {
// unwrap proxy
const childType = getElementType(child)
Expand Down

0 comments on commit 56fdd05

Please sign in to comment.