From 4d8f0449d9d08528cc1aaba0aa09d1d90e12d3dd Mon Sep 17 00:00:00 2001 From: Paul O'Shannessy Date: Thu, 29 Aug 2013 17:32:53 -0700 Subject: [PATCH] React.isValidClass Sometimes you may need to detect if a value is a valid React class constructor. This enables that and prevents future consumers from getting caught in the trap of depending on an internal implementation detail we might change. Currently this works for classes created with `React.createClass` as well as `React.DOM.*`. --- src/core/React.js | 1 + src/core/ReactCompositeComponent.js | 13 ++++++++++ .../__tests__/ReactCompositeComponent-test.js | 26 +++++++++++++++++++ src/core/__tests__/ReactDOM-test.js | 9 ++++--- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/core/React.js b/src/core/React.js index 2c63e8795b..511742b5c2 100644 --- a/src/core/React.js +++ b/src/core/React.js @@ -50,6 +50,7 @@ var React = { ), renderComponentToString: ReactServerRendering.renderComponentToString, unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode, + isValidClass: ReactCompositeComponent.isValidClass, isValidComponent: ReactComponent.isValidComponent }; diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index aab39a4265..08edadb7ef 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -956,6 +956,19 @@ var ReactCompositeComponent = { return ConvenienceConstructor; }, + /** + * Checks if a value is a valid component constructor. + * + * @param {*} + * @return {boolean} + * @public + */ + isValidClass: function(componentClass) { + return componentClass instanceof Function && + 'componentConstructor' in componentClass && + componentClass.componentConstructor instanceof Function; + }, + /** * TODO: Delete this when all callers have been updated to rely on this * behavior being the default. diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index 752ab19fb4..bc9db48ef8 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -381,4 +381,30 @@ describe('ReactCompositeComponent', function() { ); }); + it('should detect valid CompositeComponent classes', function() { + var Component = React.createClass({ + render: function() { + return
; + } + }); + + expect(React.isValidClass(Component)).toBe(true); + }); + + it('should detect invalid CompositeComponent classes', function() { + var FnComponent = function() { + return false; + } + + var NullComponent = null; + + var TrickFnComponent = function() { + return true; + } + TrickFnComponent.componentConstructor = true; + + expect(React.isValidClass(FnComponent)).toBe(false); + expect(React.isValidClass(NullComponent)).toBe(false); + expect(React.isValidClass(TrickFnComponent)).toBe(false); + }); }); diff --git a/src/core/__tests__/ReactDOM-test.js b/src/core/__tests__/ReactDOM-test.js index fdd88c6757..bd7ce73fdb 100644 --- a/src/core/__tests__/ReactDOM-test.js +++ b/src/core/__tests__/ReactDOM-test.js @@ -23,11 +23,10 @@ var React = require('React'); var ReactDOM = require('ReactDOM'); -var ReactTestUtils = require('ReactTestUtils'); -var React = require('React'); var ReactMount = require('ReactMount'); +var ReactTestUtils = require('ReactTestUtils'); -describe('ref swapping', function() { +describe('ReactDOM', function() { // TODO: uncomment this test once we can run in phantom, which // supports real submit events. /* @@ -115,4 +114,8 @@ describe('ref swapping', function() { var dog = root.childNodes[0]; expect(dog.className).toBe('bigdog'); }); + + it('should be a valid class', function() { + expect(React.isValidClass(ReactDOM.div)).toBe(true); + }); });