Skip to content

Commit cf165a6

Browse files
committed
fix: dont hot-swap registered components, #1050
1 parent ca3efeb commit cf165a6

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

Diff for: src/reactHotLoader.js

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
getProxyById,
1010
createProxyForType,
1111
isTypeBlacklisted,
12+
registerComponent,
1213
} from './reconciler/proxies'
1314
import configuration from './configuration'
1415
import logger from './logger'
@@ -62,6 +63,7 @@ const reactHotLoader = {
6263
}
6364

6465
updateProxyById(id, type)
66+
registerComponent(type)
6567
}
6668
},
6769

Diff for: src/reconciler/hotReplacementRender.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { PROXY_IS_MOUNTED, PROXY_KEY, UNWRAP_PROXY } from '../proxy'
33
import {
44
getIdByType,
55
getProxyByType,
6+
isRegisteredComponent,
67
isTypeBlacklisted,
78
updateProxyById,
89
} from './proxies'
@@ -99,7 +100,7 @@ const equalClasses = (a, b) => {
99100
}
100101

101102
export const areSwappable = (a, b) => {
102-
// both are registered components
103+
// both are registered components and have the same name
103104
if (getIdByType(b) && getIdByType(a) === getIdByType(b)) {
104105
return true
105106
}
@@ -401,7 +402,12 @@ const hotReplacementRender = (instance, stack) => {
401402
throw new Error('React-hot-loader: wrong configuration')
402403
}
403404

404-
if (areSwappable(childType, stackChild.type)) {
405+
if (
406+
isRegisteredComponent(childType) ||
407+
isRegisteredComponent(stackChild.type)
408+
) {
409+
// one of elements are registered via babel plugin, and should not be handled by hot swap
410+
} else if (areSwappable(childType, stackChild.type)) {
405411
// they are both registered, or have equal code/displayname/signature
406412

407413
// update proxy using internal PROXY_KEY

Diff for: src/reconciler/proxies.js

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { resetClassProxies } from '../proxy/createClassProxy'
33

44
let proxiesByID
55
let blackListedProxies
6+
let registeredComponents
67
let idsByType
78

89
let elementCount = 0
@@ -16,6 +17,9 @@ export const isProxyType = type => type[PROXY_KEY]
1617
export const getProxyById = id => proxiesByID[id]
1718
export const getProxyByType = type => getProxyById(getIdByType(type))
1819

20+
export const registerComponent = type => registeredComponents.set(type, 1)
21+
export const isRegisteredComponent = type => registeredComponents.has(type)
22+
1923
export const setStandInOptions = options => {
2024
renderOptions = options
2125
}
@@ -42,6 +46,7 @@ export const resetProxies = () => {
4246
proxiesByID = {}
4347
idsByType = new WeakMap()
4448
blackListedProxies = new WeakMap()
49+
registeredComponents = new WeakMap()
4550
resetClassProxies()
4651
}
4752

Diff for: test/reconciler.test.js

+48
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,54 @@ describe('reconciler', () => {
157157
expect(areComponentsEqual(second.Component, third.Component)).toBe(false)
158158
})
159159

160+
it('should hot-swap only internal components', () => {
161+
let An0
162+
let An1
163+
let Bn0
164+
let Bn1
165+
let App
166+
{
167+
const A = () => <div>A</div>
168+
const B = () => <div>A</div>
169+
App = () => (
170+
<div>
171+
<A />
172+
<B />
173+
</div>
174+
)
175+
An0 = A
176+
Bn0 = B
177+
reactHotLoader.register(App, 'App', 'test-hot-swap.js')
178+
reactHotLoader.register(B, 'B0', 'test-hot-swap.js')
179+
}
180+
const wrapper = mount(
181+
<div>
182+
<App />
183+
</div>,
184+
)
185+
{
186+
const A = () => <div>A</div>
187+
const B = () => <div>A</div>
188+
App = () => (
189+
<div>
190+
<A />
191+
<B />
192+
</div>
193+
)
194+
An1 = A
195+
Bn1 = B
196+
reactHotLoader.register(App, 'App', 'test-hot-swap.js')
197+
reactHotLoader.register(B, 'B1', 'test-hot-swap.js')
198+
}
199+
incrementGeneration()
200+
wrapper.setProps({ update: 'now' })
201+
202+
// A-s are similar, and got merged
203+
expect(<An0 />.type).toEqual(<An1 />.type)
204+
// B-s are simlar, but known to be different types - not merged
205+
expect(<Bn0 />.type).not.toEqual(<Bn1 />.type)
206+
})
207+
160208
it('should regenerate internal component without AppContainer', () => {
161209
const first = spyComponent(
162210
({ children }) => <b>{children}</b>,

0 commit comments

Comments
 (0)