mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Do not patch prototypes with render exposed only as a getter. (#898)
* Do not patch prototypes with render exposed only as a getter. * Use Object.getOwnPropertyDescriptor to make things simpler. * Get the prototype which has the render method.
This commit is contained in:
parent
ee717af088
commit
bf467e64af
|
@ -16,24 +16,37 @@ export default (handleError = () => {}) => {
|
||||||
|
|
||||||
React.createElement = function (Component, ...rest) {
|
React.createElement = function (Component, ...rest) {
|
||||||
if (typeof Component === 'function') {
|
if (typeof Component === 'function') {
|
||||||
|
// We need to get the prototype which has the render method.
|
||||||
|
// It's possible to have render inside a deeper prototype due to
|
||||||
|
// class extending.
|
||||||
|
const prototypeWithRender = getRenderPrototype(Component)
|
||||||
const { prototype } = Component
|
const { prototype } = Component
|
||||||
|
|
||||||
// assumes it's a class component if render method exists.
|
// assumes it's a class component if render method exists.
|
||||||
const isClassComponent = Boolean(prototype && prototype.render) ||
|
const isClassComponent = Boolean(prototypeWithRender) ||
|
||||||
// subclass of React.Component or PureComponent with no render method.
|
// subclass of React.Component or PureComponent with no render method.
|
||||||
// There's no render method in prototype
|
// There's no render method in prototype
|
||||||
// when it's created with class-properties.
|
// when it's created with class-properties.
|
||||||
prototype instanceof React.Component ||
|
prototype instanceof React.Component ||
|
||||||
prototype instanceof React.PureComponent
|
prototype instanceof React.PureComponent
|
||||||
|
|
||||||
|
let dynamicWrapper = withWrapOwnRender
|
||||||
|
|
||||||
if (isClassComponent) {
|
if (isClassComponent) {
|
||||||
if (prototype.render) {
|
if (prototypeWithRender) {
|
||||||
prototype.render = wrapRender(prototype.render)
|
// Sometimes render method is created with only a getter.
|
||||||
|
// In that case we can't override it with a prototype. We need to
|
||||||
|
// do it dynamically.
|
||||||
|
if (canOverrideRender(prototypeWithRender)) {
|
||||||
|
prototypeWithRender.render = wrapRender(prototypeWithRender.render)
|
||||||
|
} else {
|
||||||
|
dynamicWrapper = withWrapRenderAlways
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap the render method in runtime when the component initialized
|
// wrap the render method in runtime when the component initialized
|
||||||
// for class-properties.
|
// for class-properties.
|
||||||
Component = wrap(Component, withWrapOwnRender)
|
Component = wrap(Component, dynamicWrapper)
|
||||||
} else {
|
} else {
|
||||||
// stateless component
|
// stateless component
|
||||||
Component = wrapRender(Component)
|
Component = wrapRender(Component)
|
||||||
|
@ -73,6 +86,14 @@ export default (handleError = () => {}) => {
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withWrapRenderAlways (fn, ...args) {
|
||||||
|
const result = fn.apply(this, args)
|
||||||
|
if (this.render) {
|
||||||
|
this.render = wrapRender(this.render)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrap (fn, around) {
|
function wrap (fn, around) {
|
||||||
|
@ -93,3 +114,20 @@ function wrap (fn, around) {
|
||||||
|
|
||||||
return _fn
|
return _fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRenderPrototype (Component) {
|
||||||
|
let proto = Component.prototype
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (proto.hasOwnProperty('render')) return proto
|
||||||
|
proto = Object.getPrototypeOf(proto)
|
||||||
|
if (!proto) return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function canOverrideRender (prototype) {
|
||||||
|
const descriptor = Object.getOwnPropertyDescriptor(prototype, 'render')
|
||||||
|
if (!descriptor) return true
|
||||||
|
|
||||||
|
return descriptor.writable
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue