From 177d9fc3b3fb0c3aec3803c5947b65667d92adea Mon Sep 17 00:00:00 2001 From: Kye Hohenberger Date: Mon, 24 Apr 2017 21:24:03 -0600 Subject: [PATCH] check proptypes only on element creation like react. --- src/index.js | 47 ++++++++++++++++++++++++++++++----------------- test/component.js | 8 ++++++++ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/index.js b/src/index.js index 472098e..46fe3f0 100644 --- a/src/index.js +++ b/src/index.js @@ -270,10 +270,35 @@ function statelessComponentHook(Ctor) { return Wrapped; } +function validatePropTypes (vnode) { + if (DEV) { + let componentClass = typeof vnode.nodeName === "function" + ? vnode.nodeName + : vnode.type; + + if (typeof componentClass !== "function") return; + let name = componentClass.displayName || componentClass.name; + let propTypes = componentClass.propTypes; + if (propTypes) { + let props = vnode.props; + if ( + !(vnode.props && vnode.props.children) && + vnode.children && + vnode.children.length + ) { + props.children = vnode.children; + } + propsHook(props); + PropTypes.checkPropTypes(propTypes, props, 'prop', name); + } + } +} function createElement(...args) { upgradeToVNodes(args, 2); - return normalizeVNode(h(...args)); + let node = h(...args); + validatePropTypes(node); + return normalizeVNode(node); } @@ -293,7 +318,6 @@ function normalizeVNode(vnode) { } applyEventNormalization(vnode); - return vnode; } @@ -315,10 +339,11 @@ function cloneElement(element, props, ...children) { else if (props && props.children) { cloneArgs.push(props.children); } - return normalizeVNode(preactCloneElement(...cloneArgs)); + let newNode = preactCloneElement(...cloneArgs); + validatePropTypes(newNode); + return normalizeVNode(newNode); } - function isValidElement(element) { return element && ((element instanceof VNode) || element.$$typeof===REACT_ELEMENT_TYPE); } @@ -489,7 +514,7 @@ function multihook(hooks, skipDuplicates) { function newComponentHook(props, context) { - propsHook.call(this, props, context); + propsHook(props, context); this.componentWillReceiveProps = multihook([propsHook, this.componentWillReceiveProps || 'componentWillReceiveProps']); this.render = multihook([propsHook, beforeRender, this.render || 'render', afterRender]); } @@ -509,20 +534,8 @@ function propsHook(props, context) { props.children[0] = props.children; } } - - // add proptype checking - if (DEV) { - let ctor = typeof this==='function' ? this : this.constructor, - propTypes = this.propTypes || ctor.propTypes; - const displayName = this.displayName || ctor.name; - - if (propTypes) { - PropTypes.checkPropTypes(propTypes, props, 'prop', displayName); - } - } } - function beforeRender(props) { currentComponent = this; } diff --git a/test/component.js b/test/component.js index 639ed37..d290d68 100644 --- a/test/component.js +++ b/test/component.js @@ -191,6 +191,14 @@ describe('components', () => { 'Warning: Failed prop type: Invalid prop `bool` of type `string` supplied to `' + name + '`, expected `boolean`.' ); + console.error.reset(); + + const clone = React.cloneElement(); + React.render(clone, scratch); + expect(console.error).to.have.been.calledWithMatch( + 'Warning: Failed prop type: Invalid prop `func` of type `string` supplied to `' + name + '`, expected `function`.' + ); + console.error.restore(); }