Skip to content

Commit 09e48eb

Browse files
committed
fix: Support Context.Provider reload and React.memo, fixes #1169
1 parent f995b0d commit 09e48eb

File tree

5 files changed

+39
-13
lines changed

5 files changed

+39
-13
lines changed

Diff for: src/internal/reactUtils.js

+2
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,7 @@ export const isForwardType = ({ type }) =>
9393
'$$typeof' in type &&
9494
type.$$typeof === ForwardType &&
9595
ForwardType
96+
export const isContextType = type =>
97+
isContextConsumer(type) || isContextProvider(type)
9698

9799
export const getContextProvider = type => type && type._context

Diff for: src/internal/stack/hydrateFiberStack.js

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
function pushStack(stack, node) {
44
stack.type = node.type
5+
stack.elementType = node.elementType || node.type
56
stack.children = []
67
stack.instance = typeof node.type === 'function' ? node.stateNode : stack
78
stack.fiber = node

Diff for: src/reactHotLoader.js

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
isLazyType,
66
isMemoType,
77
isForwardType,
8+
isContextType,
89
} from './internal/reactUtils'
910
import { increment as incrementGeneration } from './global/generation'
1011
import {
@@ -20,6 +21,7 @@ import logger from './logger'
2021

2122
import { preactAdapter } from './adapters/preact'
2223
import {
24+
updateContext,
2325
updateForward,
2426
updateLazy,
2527
updateMemo,
@@ -73,6 +75,11 @@ const reactHotLoader = {
7375
registerComponent(updateProxyById(id, type, options).get(), 2)
7476
registerComponent(type)
7577
}
78+
if (isContextType({ type })) {
79+
updateFunctionProxyById(id, type, updateContext)
80+
updateFunctionProxyById(`${id}:provider`, type.Provider, updateContext)
81+
incrementGeneration()
82+
}
7683
if (isLazyType({ type })) {
7784
updateFunctionProxyById(id, type, updateLazy)
7885
incrementGeneration()

Diff for: src/reconciler/fiberUpdater.js

+4
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@ export const updateMemo = (target, { type }) => {
3737
export const updateForward = (target, { render }) => {
3838
target.render = render
3939
}
40+
41+
export const updateContext = () => {
42+
// nil
43+
}

Diff for: src/reconciler/hotReplacementRender.js

+25-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import reactHotLoader from '../reactHotLoader'
2222
import logger from '../logger'
2323
import configuration, { internalConfiguration } from '../configuration'
2424
import { areSwappable } from './utils'
25+
import { resolveType } from './resolver'
2526

2627
let renderStack = []
2728

@@ -224,6 +225,7 @@ const hotReplacementRender = (instance, stack) => {
224225
const { children } = stack
225226

226227
flow.forEach((child, index) => {
228+
let childType = child.type
227229
const stackChild = children[index]
228230
const next = instance => {
229231
// copy over props as long new component may be hidden inside them
@@ -258,12 +260,13 @@ const hotReplacementRender = (instance, stack) => {
258260
return
259261
}
260262

261-
if (typeof child.type !== typeof stackChild.type) {
263+
// comparing rendered type to fiber.ElementType
264+
if (typeof childType !== typeof stackChild.elementType) {
262265
// Portals could generate undefined !== null
263-
if (child.type && stackChild.type) {
266+
if (childType && stackChild.type) {
264267
logger.warn(
265268
'React-hot-loader: got ',
266-
child.type,
269+
childType,
267270
'instead of',
268271
stackChild.type,
269272
)
@@ -277,6 +280,7 @@ const hotReplacementRender = (instance, stack) => {
277280
if (stackChild.children && stackChild.children[0]) {
278281
scheduleInstanceUpdate(stackChild.children[0].instance)
279282
}
283+
childType = childType.type || childType
280284
}
281285

282286
if (isForwardType(child)) {
@@ -285,24 +289,22 @@ const hotReplacementRender = (instance, stack) => {
285289
try {
286290
next({
287291
children: (child.props ? child.props.children : child.children[0])(
288-
stackContext().get(getContextProvider(child.type)) ||
289-
child.type[CONTEXT_CURRENT_VALUE],
292+
stackContext().get(getContextProvider(childType)) ||
293+
childType[CONTEXT_CURRENT_VALUE],
290294
),
291295
})
292296
} catch (e) {
293297
// do nothing, yet
294298
}
295-
} else if (typeof child.type !== 'function') {
299+
} else if (typeof childType !== 'function') {
296300
// React
297-
let childName = child.type
298-
? getComponentDisplayName(child.type)
299-
: 'empty'
301+
let childName = childType ? getComponentDisplayName(childType) : 'empty'
300302
let extraContext = stackContext()
301303

302304
if (isContextProvider(child)) {
303305
extraContext = new Map(extraContext)
304306
extraContext.set(
305-
getContextProvider(child.type),
307+
getContextProvider(childType),
306308
{
307309
...(child.nextProps || {}),
308310
...(child.props || {}),
@@ -313,7 +315,7 @@ const hotReplacementRender = (instance, stack) => {
313315

314316
renderStack.push({
315317
name: childName,
316-
type: child.type,
318+
type: childType,
317319
props: stack.instance.props,
318320
context: extraContext,
319321
})
@@ -330,11 +332,16 @@ const hotReplacementRender = (instance, stack) => {
330332
)
331333
renderStack.pop()
332334
} else {
333-
if (child.type === stackChild.type) {
335+
if (childType === stackChild.type) {
334336
next(stackChild.instance)
335337
} else {
336338
// unwrap proxy
337-
const childType = getElementType(child)
339+
let childType = getElementType(child)
340+
341+
if (isMemoType(child)) {
342+
childType = childType.type || childType
343+
}
344+
338345
if (!stackChild.type[PROXY_KEY]) {
339346
if (!reactHotLoader.IS_REACT_MERGE_ENABLED) {
340347
if (isTypeBlacklisted(stackChild.type)) {
@@ -351,6 +358,11 @@ const hotReplacementRender = (instance, stack) => {
351358
isRegisteredComponent(stackChild.type)
352359
) {
353360
// one of elements are registered via babel plugin, and should not be handled by hot swap
361+
if (resolveType(childType) === resolveType(stackChild.type)) {
362+
next(stackChild.instance)
363+
} else {
364+
// one component replace another. This is normal situation
365+
}
354366
} else if (areSwappable(childType, stackChild.type)) {
355367
// they are both registered, or have equal code/displayname/signature
356368

0 commit comments

Comments
 (0)