mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Don't mutate passed-in props, take 2
This commit is contained in:
@@ -679,7 +679,7 @@ var ReactCompositeComponentMixin = {
|
||||
this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
|
||||
|
||||
this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
|
||||
this._processProps(this.props);
|
||||
this.props = this._processProps(this.props);
|
||||
|
||||
if (this.__reactAutoBindMap) {
|
||||
this._bindAutoBindMethods();
|
||||
@@ -853,12 +853,15 @@ var ReactCompositeComponentMixin = {
|
||||
|
||||
/**
|
||||
* Processes props by setting default values for unspecified props and
|
||||
* asserting that the props are valid.
|
||||
* asserting that the props are valid. Does not mutate its argument; returns
|
||||
* a new props object with defaults merged in.
|
||||
*
|
||||
* @param {object} props
|
||||
* @param {object} newProps
|
||||
* @return {object}
|
||||
* @private
|
||||
*/
|
||||
_processProps: function(props) {
|
||||
_processProps: function(newProps) {
|
||||
var props = merge(newProps);
|
||||
var defaultProps = this._defaultProps;
|
||||
for (var propName in defaultProps) {
|
||||
if (typeof props[propName] === 'undefined') {
|
||||
@@ -869,6 +872,7 @@ var ReactCompositeComponentMixin = {
|
||||
if (propTypes) {
|
||||
this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop);
|
||||
}
|
||||
return props;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -920,8 +924,7 @@ var ReactCompositeComponentMixin = {
|
||||
|
||||
var nextProps = this.props;
|
||||
if (this._pendingProps != null) {
|
||||
nextProps = this._pendingProps;
|
||||
this._processProps(nextProps);
|
||||
nextProps = this._processProps(this._pendingProps);
|
||||
this._pendingProps = null;
|
||||
|
||||
this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
|
||||
|
||||
@@ -213,6 +213,47 @@ describe('ReactCompositeComponent', function() {
|
||||
reactComponentExpect(instance3).scalarPropsEqual({key: null});
|
||||
});
|
||||
|
||||
it('should not mutate passed-in props object', function() {
|
||||
var Component = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {key: 'testKey'};
|
||||
},
|
||||
render: function() {
|
||||
return <span />;
|
||||
}
|
||||
});
|
||||
|
||||
var inputProps = {};
|
||||
var instance1 = Component(inputProps);
|
||||
ReactTestUtils.renderIntoDocument(instance1);
|
||||
expect(instance1.props.key).toBe('testKey');
|
||||
|
||||
// We don't mutate the input, just in case the caller wants to do something
|
||||
// with it after using it to instantiate a component
|
||||
expect(inputProps.key).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should use default prop value when removing a key', function() {
|
||||
var Component = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {fruit: 'persimmon'};
|
||||
},
|
||||
render: function() {
|
||||
return <span />;
|
||||
}
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
var instance = React.renderComponent(
|
||||
<Component fruit="mango" />,
|
||||
container
|
||||
);
|
||||
expect(instance.props.fruit).toBe('mango');
|
||||
|
||||
React.renderComponent(<Component />, container);
|
||||
expect(instance.props.fruit).toBe('persimmon');
|
||||
});
|
||||
|
||||
it('should normalize props with default values', function() {
|
||||
var Component = React.createClass({
|
||||
propTypes: {key: ReactPropTypes.string.isRequired},
|
||||
|
||||
Reference in New Issue
Block a user