Skip to content

Commit ff7d5c7

Browse files
authored
Merge pull request #1261 from gaearon/type-comparison
feat: transparent class wrapping
2 parents 1023b98 + 33bfe26 commit ff7d5c7

File tree

3 files changed

+72
-46
lines changed

3 files changed

+72
-46
lines changed

src/reactHotLoader.js

+51-44
Original file line numberDiff line numberDiff line change
@@ -115,55 +115,62 @@ const reactHotLoader = {
115115

116116
reactHotLoader.IS_REACT_MERGE_ENABLED = true;
117117
configuration.showReactDomPatchNotification = false;
118-
// console.warn('react-🔥-loader activated.');
119-
}
120-
/* eslint-enable */
121-
if (!React.createElement.isPatchedByReactHotLoader) {
122-
const originalCreateElement = React.createElement;
123-
// Trick React into rendering a proxy so that
124-
// its state is preserved when the class changes.
125-
// This will update the proxy if it's for a known type.
126-
React.createElement = (type, ...args) => originalCreateElement(resolveType(type), ...args);
127-
React.createElement.isPatchedByReactHotLoader = true;
118+
119+
if (ReactDOM.setHotTypeResolver) {
120+
configuration.intergratedResolver = true;
121+
ReactDOM.setHotTypeResolver(resolveType);
122+
}
128123
}
129124

130-
if (!React.cloneElement.isPatchedByReactHotLoader) {
131-
const originalCloneElement = React.cloneElement;
132-
133-
React.cloneElement = (element, ...args) => {
134-
const newType = element.type && resolveType(element.type);
135-
if (newType && newType !== element.type) {
136-
return originalCloneElement(
137-
{
138-
...element,
139-
type: newType,
140-
},
141-
...args,
142-
);
143-
}
144-
return originalCloneElement(element, ...args);
145-
};
125+
if (!configuration.intergratedResolver) {
126+
/* eslint-enable */
127+
if (!React.createElement.isPatchedByReactHotLoader) {
128+
const originalCreateElement = React.createElement;
129+
// Trick React into rendering a proxy so that
130+
// its state is preserved when the class changes.
131+
// This will update the proxy if it's for a known type.
132+
React.createElement = (type, ...args) => originalCreateElement(resolveType(type), ...args);
133+
React.createElement.isPatchedByReactHotLoader = true;
134+
}
146135

147-
React.cloneElement.isPatchedByReactHotLoader = true;
148-
}
136+
if (!React.cloneElement.isPatchedByReactHotLoader) {
137+
const originalCloneElement = React.cloneElement;
138+
139+
React.cloneElement = (element, ...args) => {
140+
const newType = element.type && resolveType(element.type);
141+
if (newType && newType !== element.type) {
142+
return originalCloneElement(
143+
{
144+
...element,
145+
type: newType,
146+
},
147+
...args,
148+
);
149+
}
150+
return originalCloneElement(element, ...args);
151+
};
149152

150-
if (!React.createFactory.isPatchedByReactHotLoader) {
151-
// Patch React.createFactory to use patched createElement
152-
// because the original implementation uses the internal,
153-
// unpatched ReactElement.createElement
154-
React.createFactory = type => {
155-
const factory = React.createElement.bind(null, type);
156-
factory.type = type;
157-
return factory;
158-
};
159-
React.createFactory.isPatchedByReactHotLoader = true;
160-
}
153+
React.cloneElement.isPatchedByReactHotLoader = true;
154+
}
161155

162-
if (!React.Children.only.isPatchedByReactHotLoader) {
163-
const originalChildrenOnly = React.Children.only;
164-
// Use the same trick as React.createElement
165-
React.Children.only = children => originalChildrenOnly({ ...children, type: resolveType(children.type) });
166-
React.Children.only.isPatchedByReactHotLoader = true;
156+
if (!React.createFactory.isPatchedByReactHotLoader) {
157+
// Patch React.createFactory to use patched createElement
158+
// because the original implementation uses the internal,
159+
// unpatched ReactElement.createElement
160+
React.createFactory = type => {
161+
const factory = React.createElement.bind(null, type);
162+
factory.type = type;
163+
return factory;
164+
};
165+
React.createFactory.isPatchedByReactHotLoader = true;
166+
}
167+
168+
if (!React.Children.only.isPatchedByReactHotLoader) {
169+
const originalChildrenOnly = React.Children.only;
170+
// Use the same trick as React.createElement
171+
React.Children.only = children => originalChildrenOnly({ ...children, type: resolveType(children.type) });
172+
React.Children.only.isPatchedByReactHotLoader = true;
173+
}
167174
}
168175

169176
if (React.useEffect && !React.useState.isPatchedByReactHotLoader) {

src/reconciler/componentComparator.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { areSwappable } from './utils';
55
import { PROXY_KEY, UNWRAP_PROXY } from '../proxy';
66
import { resolveType } from './resolver';
77
import logger from '../logger';
8+
import configuration from '../configuration';
89

910
const getInnerComponentType = component => {
1011
const unwrapper = component[UNWRAP_PROXY];
@@ -89,11 +90,13 @@ const compareComponents = (oldType, newType, setNewType, baseType) => {
8990
const knownPairs = new WeakMap();
9091
const emptyMap = new WeakMap();
9192

92-
export const hotComponentCompare = (oldType, newType, setNewType, baseType) => {
93+
export const hotComponentCompare = (oldType, preNewType, setNewType, baseType) => {
9394
const hotActive = hotComparisonOpen();
95+
const newType = configuration.intergratedResolver ? resolveType(preNewType) : preNewType;
9496
let result = oldType === newType;
9597

9698
if (
99+
result ||
97100
!isReloadableComponent(oldType) ||
98101
!isReloadableComponent(newType) ||
99102
isColdType(oldType) ||

src/webpack/patch.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ const additional = {
3434
'if (current!== null&&current.type===element.type)',
3535
'if (current!== null&&hotCompareElements(current.type,element.type,hotUpdateChild(current)))',
3636
],
37+
38+
'16.8-type': [
39+
'function createFiberFromTypeAndProps(type, // React$ElementType\nkey, pendingProps, owner, mode, expirationTime) {',
40+
'function createFiberFromTypeAndProps(type, // React$ElementType\nkey, pendingProps, owner, mode, expirationTime) {type = hotResolveType(type);',
41+
],
42+
43+
'16.8-type-compact': [
44+
'function createFiberFromTypeAndProps(type,// React$ElementType\nkey,pendingProps,owner,mode,expirationTime){',
45+
'function createFiberFromTypeAndProps(type,// React$ElementType\nkey,pendingProps,owner,mode,expirationTime){type = hotResolveType(type);',
46+
]
3747
};
3848

3949
const ReactHotLoaderInjection = `
@@ -45,6 +55,9 @@ var hotUpdateChild = function (child) {
4555
}
4656
}
4757
};
58+
var hotResolveType = function (type) {
59+
return type;
60+
};
4861
var hotCompareElements = function (oldType, newType) {
4962
return oldType === newType
5063
};
@@ -79,6 +92,9 @@ var ReactDOM = {
7992
setHotElementComparator: function (newComparator) {
8093
hotCompareElements = newComparator
8194
},
95+
setHotTypeResolver: function (newResolver) {
96+
hotResolveType = newResolver;
97+
},
8298
`;
8399

84100
const defaultEnd = ['var ReactDOM = {', ReactHotLoaderInjection];
@@ -92,7 +108,7 @@ const injectionEnd = {
92108
'16.4-compact': defaultEndCompact,
93109
};
94110

95-
const sign = '/* 🔥 this is hot-loader/react-dom 🔥 */';
111+
const sign = '/* 🔥 this is hot-loader/react-dom 4.8+ 🔥 */';
96112

97113
function additionalTransform(source) {
98114
for (const key in additional) {

0 commit comments

Comments
 (0)