diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 955d305f69e0c..752b86d7a6a64 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -48,30 +48,15 @@ src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js * includes the owner name when passing null, undefined, boolean, or number src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee -* throws if no render function is defined * renders based on context in the constructor -* should throw with non-object in the initial state property -* warns when classic properties are defined on the instance, but does not invoke them. -* should warn when misspelling shouldComponentUpdate -* should warn when misspelling componentWillReceiveProps * supports this.context passed via getChildContext src/isomorphic/modern/class/__tests__/ReactES6Class-test.js -* throws if no render function is defined * renders based on context in the constructor -* should throw with non-object in the initial state property -* warns when classic properties are defined on the instance, but does not invoke them. -* should warn when misspelling shouldComponentUpdate -* should warn when misspelling componentWillReceiveProps * supports this.context passed via getChildContext src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts -* throws if no render function is defined * renders based on context in the constructor -* should throw with non-object in the initial state property -* warns when classic properties are defined on the instance, but does not invoke them. -* should warn when misspelling shouldComponentUpdate -* should warn when misspelling componentWillReceiveProps * supports this.context passed via getChildContext src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js @@ -538,7 +523,6 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js * should warn about `setState` in render * should warn about `setState` in getChildContext * should warn when shouldComponentUpdate() returns undefined -* should warn when componentDidUnmount method is defined * should pass context to children when not owner * should pass context when re-rendered for static child * should pass context when re-rendered for static child within a composite component diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 1a0c13f8dd38d..2a79702cc4b51 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -350,30 +350,40 @@ src/isomorphic/modern/class/__tests__/ReactClassEquivalence-test.js src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee * preserves the name of the class for use in error messages +* throws if no render function is defined * renders a simple stateless component with prop * renders based on state using initial values in this.props * renders based on state using props in the constructor * renders only once when setting state in componentWillMount +* should throw with non-object in the initial state property * should render with null in the initial state property * setState through an event handler * should not implicitly bind event handlers * renders using forceUpdate even when there is no state * will call all the normal life cycle methods +* warns when classic properties are defined on the instance, but does not invoke them. +* should warn when misspelling shouldComponentUpdate +* should warn when misspelling componentWillReceiveProps * should throw AND warn when trying to access classic APIs * supports classic refs * supports drilling through to the DOM using findDOMNode src/isomorphic/modern/class/__tests__/ReactES6Class-test.js * preserves the name of the class for use in error messages +* throws if no render function is defined * renders a simple stateless component with prop * renders based on state using initial values in this.props * renders based on state using props in the constructor * renders only once when setting state in componentWillMount +* should throw with non-object in the initial state property * should render with null in the initial state property * setState through an event handler * should not implicitly bind event handlers * renders using forceUpdate even when there is no state * will call all the normal life cycle methods +* warns when classic properties are defined on the instance, but does not invoke them. +* should warn when misspelling shouldComponentUpdate +* should warn when misspelling componentWillReceiveProps * should throw AND warn when trying to access classic APIs * supports classic refs * supports drilling through to the DOM using findDOMNode @@ -385,15 +395,20 @@ src/isomorphic/modern/class/__tests__/ReactPureComponent-test.js src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts * preserves the name of the class for use in error messages +* throws if no render function is defined * renders a simple stateless component with prop * renders based on state using initial values in this.props * renders based on state using props in the constructor * renders only once when setting state in componentWillMount +* should throw with non-object in the initial state property * should render with null in the initial state property * setState through an event handler * should not implicitly bind event handlers * renders using forceUpdate even when there is no state * will call all the normal life cycle methods +* warns when classic properties are defined on the instance, but does not invoke them. +* should warn when misspelling shouldComponentUpdate +* should warn when misspelling componentWillReceiveProps * should throw AND warn when trying to access classic APIs * supports classic refs * supports drilling through to the DOM using findDOMNode @@ -1002,6 +1017,7 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js * should silently allow `setState`, not call cb on unmounting components * should cleanup even if render() fatals * should call componentWillUnmount before unmounting +* should warn when componentDidUnmount method is defined * should skip update when rerendering element in container * only renders once if updated in componentWillReceiveProps * should allow access to findDOMNode in componentWillUnmount diff --git a/src/renderers/shared/fiber/ReactFiberClassComponent.js b/src/renderers/shared/fiber/ReactFiberClassComponent.js index df1ceaa3bec11..8ed2e815c985d 100644 --- a/src/renderers/shared/fiber/ReactFiberClassComponent.js +++ b/src/renderers/shared/fiber/ReactFiberClassComponent.js @@ -24,6 +24,11 @@ var { var { isMounted } = require('ReactFiberTreeReflection'); var ReactInstanceMap = require('ReactInstanceMap'); var shallowEqual = require('shallowEqual'); +var warning = require('warning'); +var invariant = require('invariant'); + + +const isArray = Array.isArray; module.exports = function(scheduleUpdate : (fiber: Fiber) => void) { @@ -91,6 +96,98 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) { return true; } + function getName(workInProgress: Fiber, inst: any): string { + const type = workInProgress.type; + const constructor = inst && inst.constructor; + return ( + type.displayName || (constructor && constructor.displayName) || + type.name || (constructor && constructor.name) || + 'A Component' + ); + } + + function checkClassInstance(workInProgress: Fiber, inst: any) { + if (__DEV__) { + const name = getName(workInProgress, inst); + const renderPresent = inst.render; + warning( + renderPresent, + '%s(...): No `render` method found on the returned component ' + + 'instance: you may have forgotten to define `render`.', + name + ); + const noGetInitialStateOnES6 = ( + !inst.getInitialState || + inst.getInitialState.isReactClassApproved + ); + warning( + noGetInitialStateOnES6, + 'getInitialState was defined on %s, a plain JavaScript class. ' + + 'This is only supported for classes created using React.createClass. ' + + 'Did you mean to define a state property instead?', + name + ); + const noGetDefaultPropsOnES6 = ( + !inst.getDefaultProps || + inst.getDefaultProps.isReactClassApproved + ); + warning( + noGetDefaultPropsOnES6, + 'getDefaultProps was defined on %s, a plain JavaScript class. ' + + 'This is only supported for classes created using React.createClass. ' + + 'Use a static property to define defaultProps instead.', + name + ); + const noInstancePropTypes = !inst.propTypes; + warning( + noInstancePropTypes, + 'propTypes was defined as an instance property on %s. Use a static ' + + 'property to define propTypes instead.', + name, + ); + const noInstanceContextTypes = !inst.contextTypes; + warning( + noInstanceContextTypes, + 'contextTypes was defined as an instance property on %s. Use a static ' + + 'property to define contextTypes instead.', + name, + ); + const noComponentShouldUpdate = typeof inst.componentShouldUpdate !== 'function'; + warning( + noComponentShouldUpdate, + '%s has a method called ' + + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + + 'The name is phrased as a question because the function is ' + + 'expected to return a value.', + name + ); + const noComponentDidUnmount = typeof inst.componentDidUnmount !== 'function'; + warning( + noComponentDidUnmount, + '%s has a method called ' + + 'componentDidUnmount(). But there is no such lifecycle method. ' + + 'Did you mean componentWillUnmount()?', + name + ); + const noComponentWillRecieveProps = typeof inst.componentWillRecieveProps !== 'function'; + warning( + noComponentWillRecieveProps, + '%s has a method called ' + + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', + name + ); + } + + const instanceState = inst.state; + if (instanceState && (typeof instanceState !== 'object' || isArray(instanceState))) { + invariant( + false, + '%s.state: must be set to an object or null', + getName(workInProgress, inst) + ); + } + } + function adoptClassInstance(workInProgress : Fiber, instance : any) : void { instance.updater = updater; workInProgress.stateNode = instance; @@ -102,6 +199,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) { const ctor = workInProgress.type; const props = workInProgress.pendingProps; const instance = new ctor(props); + checkClassInstance(workInProgress, instance); adoptClassInstance(workInProgress, instance); return instance; }