Skip to content

Commit 0b7997f

Browse files
theKasheygregberge
authored andcommitted
fix: transfer original prototype methods (#859)
* safe define displayName, fix #845 * stand children did not exists, fix #843 * improve TS documentation * add SSR+HRM example * subrender - fix deferred updates * transfer original class methods into the Proxy prototype, fixes #858 * fix tests
1 parent ffe0035 commit 0b7997f

File tree

3 files changed

+63
-4
lines changed

3 files changed

+63
-4
lines changed

Diff for: examples/typescript/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@
2222
"@types/react-dom": "^16.0.3",
2323
"react": "^16.2.0",
2424
"react-dom": "^16.2.0",
25-
"react-hot-loader": "next"
25+
"react-hot-loader": "^4.0.0-beta.22"
2626
}
2727
}

Diff for: src/proxy/createClassProxy.js

+36-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ const has = Object.prototype.hasOwnProperty
2121

2222
const proxies = new WeakMap()
2323

24+
const blackListedClassMembers = [
25+
'constructor',
26+
'render',
27+
'componentDidMount',
28+
'componentWillReceiveProps',
29+
'componentWillUnmount',
30+
31+
'getInitialState',
32+
'getDefaultProps',
33+
]
34+
2435
const defaultRenderOptions = {
2536
componentWillReceiveProps: identity,
2637
componentWillRender: identity,
@@ -72,7 +83,9 @@ function createClassProxy(InitialComponent, proxyKey, options) {
7283
}
7384

7485
function proxiedUpdate() {
75-
inject(this, proxyGeneration, injectedMembers)
86+
if (this) {
87+
inject(this, proxyGeneration, injectedMembers)
88+
}
7689
}
7790

7891
function lifeCycleWrapperFactory(wrapperName, sideEffect = identity) {
@@ -87,6 +100,24 @@ function createClassProxy(InitialComponent, proxyKey, options) {
87100
}
88101
}
89102

103+
function methodWrapperFactory(wrapperName, realMethod) {
104+
return function wrappedMethod(...rest) {
105+
return realMethod.apply(this, rest)
106+
}
107+
}
108+
109+
const fakeBasePrototype = Base =>
110+
Object.getOwnPropertyNames(Base)
111+
.filter(key => !blackListedClassMembers.includes(key))
112+
.filter(key => {
113+
const descriptor = Object.getOwnPropertyDescriptor(Base, key)
114+
return typeof descriptor.value === 'function'
115+
})
116+
.reduce((acc, key) => {
117+
acc[key] = methodWrapperFactory(key, Base[key])
118+
return acc
119+
}, {})
120+
90121
const componentDidMount = lifeCycleWrapperFactory(
91122
'componentDidMount',
92123
target => {
@@ -124,8 +155,9 @@ function createClassProxy(InitialComponent, proxyKey, options) {
124155
return renderOptions.componentDidRender(result)
125156
}
126157

127-
const defineProxyMethods = Proxy => {
158+
const defineProxyMethods = (Proxy, Base = {}) => {
128159
defineClassMembers(Proxy, {
160+
...fakeBasePrototype(Base),
129161
render: proxiedRender,
130162
componentDidMount,
131163
componentWillReceiveProps,
@@ -139,7 +171,7 @@ function createClassProxy(InitialComponent, proxyKey, options) {
139171
if (!isFunctionalComponent) {
140172
ProxyComponent = proxyClassCreator(InitialComponent, postConstructionAction)
141173

142-
defineProxyMethods(ProxyComponent)
174+
defineProxyMethods(ProxyComponent, InitialComponent.prototype)
143175

144176
ProxyFacade = ProxyComponent
145177
} else {
@@ -255,6 +287,7 @@ function createClassProxy(InitialComponent, proxyKey, options) {
255287
} else {
256288
checkLifeCycleMethods(ProxyComponent, NextComponent)
257289
Object.setPrototypeOf(ProxyComponent.prototype, NextComponent.prototype)
290+
defineProxyMethods(ProxyComponent, NextComponent.prototype)
258291
if (proxyGeneration > 1) {
259292
injectedMembers = mergeComponents(
260293
ProxyComponent,

Diff for: test/proxy/consistency.test.js

+26
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,32 @@ describe('consistency', () => {
257257
proxy.update(Update2Class)
258258
expect(instance.render()).toBe(42)
259259
})
260+
261+
it('should stand-for all class members', () => {
262+
class Initial {
263+
constructor() {
264+
this.methodB = this.methodB.bind(this)
265+
}
266+
267+
methodA() {}
268+
269+
methodB() {}
270+
271+
render() {}
272+
}
273+
274+
const proxy = createProxy(Initial)
275+
const Class = proxy.get()
276+
expect(Object.getOwnPropertyNames(Class.prototype)).toEqual([
277+
'constructor',
278+
'methodA',
279+
'methodB',
280+
'render',
281+
'componentDidMount',
282+
'componentWillReceiveProps',
283+
'componentWillUnmount',
284+
])
285+
})
260286
})
261287
})
262288

0 commit comments

Comments
 (0)