RFC 6: createReactClass updates (#12036)

* Added UNSAFE_ methods to create-class HAS_MANY list
* Added warning for UNSAFE_componentWillRecieveProps misspelling
* Bumping create-react-class package version
* Added support for static getDerivedStateFromProps mixins
This commit is contained in:
Brian Vaughn 2018-01-19 15:13:26 -08:00 committed by GitHub
parent 4c75c5bf58
commit 5530c7565b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 9 deletions

View File

@ -270,6 +270,27 @@ function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
*/ */
componentWillUnmount: 'DEFINE_MANY', componentWillUnmount: 'DEFINE_MANY',
/**
* Replacement for (deprecated) `componentWillMount`.
*
* @optional
*/
UNSAFE_componentWillMount: 'DEFINE_MANY',
/**
* Replacement for (deprecated) `componentWillReceiveProps`.
*
* @optional
*/
UNSAFE_componentWillReceiveProps: 'DEFINE_MANY',
/**
* Replacement for (deprecated) `componentWillUpdate`.
*
* @optional
*/
UNSAFE_componentWillUpdate: 'DEFINE_MANY',
// ==== Advanced methods ==== // ==== Advanced methods ====
/** /**
@ -285,6 +306,23 @@ function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
updateComponent: 'OVERRIDE_BASE' updateComponent: 'OVERRIDE_BASE'
}; };
/**
* Similar to ReactClassInterface but for static methods.
*/
var ReactClassStaticInterface = {
/**
* This method is invoked after a component is instantiated and when it
* receives new props. Return an object to update state in response to
* prop changes. Return null to indicate no change to state.
*
* If an object is returned, its keys will be merged into the existing state.
*
* @return {object || null}
* @optional
*/
getDerivedStateFromProps: 'DEFINE_MANY_MERGED'
};
/** /**
* Mapping from class specification keys to special processing functions. * Mapping from class specification keys to special processing functions.
* *
@ -519,6 +557,7 @@ function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
if (!statics) { if (!statics) {
return; return;
} }
for (var name in statics) { for (var name in statics) {
var property = statics[name]; var property = statics[name];
if (!statics.hasOwnProperty(name)) { if (!statics.hasOwnProperty(name)) {
@ -535,14 +574,25 @@ function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
name name
); );
var isInherited = name in Constructor; var isAlreadyDefined = name in Constructor;
_invariant( if (isAlreadyDefined) {
!isInherited, var specPolicy = ReactClassStaticInterface.hasOwnProperty(name)
'ReactClass: You are attempting to define ' + ? ReactClassStaticInterface[name]
'`%s` on your component more than once. This conflict may be ' + : null;
'due to a mixin.',
name _invariant(
); specPolicy === 'DEFINE_MANY_MERGED',
'ReactClass: You are attempting to define ' +
'`%s` on your component more than once. This conflict may be ' +
'due to a mixin.',
name
);
Constructor[name] = createMergedResultFunction(Constructor[name], property);
return;
}
Constructor[name] = property; Constructor[name] = property;
} }
} }
@ -852,6 +902,12 @@ function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
spec.displayName || 'A component' spec.displayName || 'A component'
); );
warning(
!Constructor.prototype.UNSAFE_componentWillRecieveProps,
'%s has a method called UNSAFE_componentWillRecieveProps(). ' +
'Did you mean UNSAFE_componentWillReceiveProps()?',
spec.displayName || 'A component'
);
} }
// Reduce time spent doing lookups by setting these on the prototype. // Reduce time spent doing lookups by setting these on the prototype.

View File

@ -1,6 +1,6 @@
{ {
"name": "create-react-class", "name": "create-react-class",
"version": "15.6.2", "version": "15.6.3",
"description": "Legacy API for creating React components.", "description": "Legacy API for creating React components.",
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",

View File

@ -522,4 +522,55 @@ describe('ReactClass-spec', () => {
'to prevent memory leaks.' 'to prevent memory leaks.'
); );
}); });
it('should support getInitialState mixin', () => {
const Component = createReactClass({
mixins: [{
getInitialState: function(props) {
return {
foo: 'foo'
};
},
}],
getInitialState: function(props) {
return {
bar: 'bar'
};
},
render: function() {
return <div />;
}
});
const instance = renderIntoDocument(<Component />);
expect(instance.state.foo).toEqual('foo');
expect(instance.state.bar).toEqual('bar');
});
it('should merge return values for static getDerivedStateFromProps mixin', () => {
const Component = createReactClass({
mixins: [{
statics: {
getDerivedStateFromProps: function(props, prevState) {
return {
foo: 'foo'
};
}
},
}],
statics: {
getDerivedStateFromProps: function(props, prevState) {
return {
bar: 'bar'
};
}
},
render: function() {
return <div />;
}
});
const state = Component.getDerivedStateFromProps();
expect(state.foo).toEqual('foo');
expect(state.bar).toEqual('bar');
});
}); });