mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
[Fiber] Complete ES6 Class related errors support (#8156)
* Print a warning in fiber for lacking render method * Reject initial non-object state in Fiber Rejects Arrays, Strings & Numbers. Allows nulls. * Centralize fiber checks on ES6 Classes * Add classic & instance property checks on fiber - check the absence of getInitialState & getDefaultProps as methods - check the absence of propTypes & contextTypes at instance-level * Convert to normalized React `warning` calls * Support lifecycle typo detection in fiber * Get the complete warnings from the existing code * Only check classInstance once Avoid rechecking while resuming * Can warn component while resuming but only once This is achieved by tracking the warning state in the Fiber structure. * Remove warning deduplication * Factor name retrieval in a getName helper * Use invariant instead of throw * Read inst.state only once for the invariant * Fix condition on the instance state * Register failing/passing fiber tests
This commit is contained in:
committed by
Sebastian Markbåge
parent
2e91a8395f
commit
430c49b9c8
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1011,6 +1026,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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user