diff --git a/src/browser/__tests__/ReactDOM-test.js b/src/browser/__tests__/ReactDOM-test.js index 2feace23ad..0e0e5d4e85 100644 --- a/src/browser/__tests__/ReactDOM-test.js +++ b/src/browser/__tests__/ReactDOM-test.js @@ -118,4 +118,5 @@ describe('ReactDOM', function() { expect(element.type).toBe('div'); expect(console.warn.argsForCall.length).toBe(0); }); + }); diff --git a/src/browser/findDOMNode.js b/src/browser/findDOMNode.js index 730580bf65..f7f75ef775 100644 --- a/src/browser/findDOMNode.js +++ b/src/browser/findDOMNode.js @@ -11,11 +11,14 @@ */ 'use strict'; + +var ReactCurrentOwner = require('ReactCurrentOwner'); var ReactInstanceMap = require('ReactInstanceMap'); var ReactMount = require('ReactMount'); var invariant = require('invariant'); var isNode = require('isNode'); +var warning = require('warning'); /** * Returns the DOM node rendered by this element. @@ -24,6 +27,21 @@ var isNode = require('isNode'); * @return {DOMElement} The root node of this element. */ function findDOMNode(componentOrElement) { + if (__DEV__) { + var owner = ReactCurrentOwner.current; + if (owner !== null) { + warning( + owner._warnedAboutRefsInRender, + '%s is accessing getDOMNode or findDOMNode inside its render(). ' + + 'render() should be a pure function of props and state. It should ' + + 'never access something that requires stale data from the previous ' + + 'render, such as refs. Move this logic to componentDidMount and ' + + 'componentDidUpdate instead.', + owner.getName() || 'A component' + ); + owner._warnedAboutRefsInRender = true; + } + } if (componentOrElement == null) { return null; } diff --git a/src/classic/class/ReactClass.js b/src/classic/class/ReactClass.js index e8136d909a..db58d92806 100644 --- a/src/classic/class/ReactClass.js +++ b/src/classic/class/ReactClass.js @@ -12,6 +12,7 @@ 'use strict'; var ReactComponent = require('ReactComponent'); +var ReactCurrentOwner = require('ReactCurrentOwner'); var ReactElement = require('ReactElement'); var ReactErrorUtils = require('ReactErrorUtils'); var ReactInstanceMap = require('ReactInstanceMap'); @@ -746,6 +747,21 @@ var ReactClassMixin = { * @final */ isMounted: function() { + if (__DEV__) { + var owner = ReactCurrentOwner.current; + if (owner !== null) { + warning( + owner._warnedAboutRefsInRender, + '%s is accessing isMounted inside its render() function. ' + + 'render() should be a pure function of props and state. It should ' + + 'never access something that requires stale data from the previous ' + + 'render, such as refs. Move this logic to componentDidMount and ' + + 'componentDidUpdate instead.', + owner.getName() || 'A component' + ); + owner._warnedAboutRefsInRender = true; + } + } var internalInstance = ReactInstanceMap.get(this); return ( internalInstance && diff --git a/src/classic/element/ReactElementValidator.js b/src/classic/element/ReactElementValidator.js index c4d2e314ad..23572ddb69 100644 --- a/src/classic/element/ReactElementValidator.js +++ b/src/classic/element/ReactElementValidator.js @@ -387,6 +387,33 @@ var ReactElementValidator = { ); // Legacy hook TODO: Warn if this is accessed validatedFactory.type = type; + + if (__DEV__) { + try { + Object.defineProperty( + validatedFactory, + 'type', + { + enumerable: false, + get: function() { + warning( + false, + 'Factory.type is deprecated. Access the class directly ' + + 'before passing it to createFactory.' + ); + Object.defineProperty(this, 'type', { + value: type + }); + return type; + } + } + ); + } catch (x) { + // IE will fail on defineProperty (es5-shim/sham too) + } + } + + return validatedFactory; } diff --git a/src/classic/element/__tests__/ReactElementValidator-test.js b/src/classic/element/__tests__/ReactElementValidator-test.js index 5781db76ad..2ee825da0c 100644 --- a/src/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/classic/element/__tests__/ReactElementValidator-test.js @@ -330,4 +330,23 @@ describe('ReactElementValidator', function() { expect(console.warn.calls[0].args[0]).toContain('use of a keyed object'); }); + it('should warn when accessing .type on an element factory', function() { + spyOn(console, 'warn'); + var TestComponent = React.createClass({ + render: function() { + return
; + } + }); + var TestFactory = React.createFactory(TestComponent); + expect(TestFactory.type).toBe(TestComponent); + expect(console.warn.argsForCall.length).toBe(1); + expect(console.warn.argsForCall[0][0]).toBe( + 'Warning: Factory.type is deprecated. Access the class directly before ' + + 'passing it to createFactory.' + ); + // Warn once, not again + expect(TestFactory.type).toBe(TestComponent); + expect(console.warn.argsForCall.length).toBe(1); + }); + }); diff --git a/src/core/__tests__/ReactComponent-test.js b/src/core/__tests__/ReactComponent-test.js index 2a2be2a974..7dd26652b6 100644 --- a/src/core/__tests__/ReactComponent-test.js +++ b/src/core/__tests__/ReactComponent-test.js @@ -254,26 +254,6 @@ describe('ReactComponent', function() { ]); }); - it('should correctly determine if a component is mounted', function() { - var Component = React.createClass({ - componentWillMount: function() { - expect(this.isMounted()).toBeFalsy(); - }, - componentDidMount: function() { - expect(this.isMounted()).toBeTruthy(); - }, - render: function() { - expect(this.isMounted()).toBeFalsy() - return ; - } - }); - - var element =