Merge pull request #4268 from jimfb/remove-setprops

Removed setProps and replaceProps (both previously deprecated)
This commit is contained in:
Jim
2015-07-02 04:47:18 -07:00
16 changed files with 45 additions and 386 deletions
@@ -121,9 +121,9 @@ describe('ReactContextValidator', function() {
},
});
var instance = <Parent foo="abc" />;
instance = ReactTestUtils.renderIntoDocument(instance);
instance.replaceProps({foo: 'def'});
var container = document.createElement('div');
React.render(<Parent foo="abc" />, container);
React.render(<Parent foo="def" />, container);
expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
expect(actualComponentWillUpdate).toEqual({foo: 'def'});
@@ -728,38 +728,6 @@ var ReactClassMixin = {
isMounted: function() {
return this.updater.isMounted(this);
},
/**
* Sets a subset of the props.
*
* @param {object} partialProps Subset of the next props.
* @param {?function} callback Called after props are updated.
* @final
* @public
* @deprecated
*/
setProps: function(partialProps, callback) {
this.updater.enqueueSetProps(this, partialProps);
if (callback) {
this.updater.enqueueCallback(this, callback);
}
},
/**
* Replace all the props.
*
* @param {object} newProps Subset of the next props.
* @param {?function} callback Called after props are updated.
* @final
* @public
* @deprecated
*/
replaceProps: function(newProps, callback) {
this.updater.enqueueReplaceProps(this, newProps);
if (callback) {
this.updater.enqueueCallback(this, callback);
}
},
};
var ReactClassComponent = function() {};
@@ -112,19 +112,11 @@ if (__DEV__) {
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
],
replaceProps: [
'replaceProps',
'Instead, call React.render again at the top level.',
],
replaceState: [
'replaceState',
'Refactor your code to use setState instead (see ' +
'https://github.com/facebook/react/issues/3236).',
],
setProps: [
'setProps',
'Instead, call React.render again at the top level.',
],
};
var defineDeprecationWarning = function(methodName, info) {
try {
@@ -98,29 +98,6 @@ var ReactNoopUpdateQueue = {
enqueueSetState: function(publicInstance, partialState) {
warnTDZ(publicInstance, 'setState');
},
/**
* Sets a subset of the props.
*
* @param {ReactClass} publicInstance The instance that should rerender.
* @param {object} partialProps Subset of the next props.
* @internal
*/
enqueueSetProps: function(publicInstance, partialProps) {
warnTDZ(publicInstance, 'setProps');
},
/**
* Replaces all of the props.
*
* @param {ReactClass} publicInstance The instance that should rerender.
* @param {object} props New props.
* @internal
*/
enqueueReplaceProps: function(publicInstance, props) {
warnTDZ(publicInstance, 'replaceProps');
},
};
module.exports = ReactNoopUpdateQueue;
@@ -346,9 +346,7 @@ describe 'ReactCoffeeScriptClass', ->
expect(-> instance.getDOMNode()).toThrow()
expect(-> instance.replaceState {}).toThrow()
expect(-> instance.isMounted()).toThrow()
expect(-> instance.setProps name: 'bar').toThrow()
expect(-> instance.replaceProps name: 'bar').toThrow()
expect(console.error.calls.length).toBe 5
expect(console.error.calls.length).toBe 3
expect(console.error.calls[0].args[0]).toContain(
'getDOMNode(...) is deprecated in plain JavaScript React classes'
)
@@ -358,12 +356,6 @@ describe 'ReactCoffeeScriptClass', ->
expect(console.error.calls[2].args[0]).toContain(
'isMounted(...) is deprecated in plain JavaScript React classes'
)
expect(console.error.calls[3].args[0]).toContain(
'setProps(...) is deprecated in plain JavaScript React classes'
)
expect(console.error.calls[4].args[0]).toContain(
'replaceProps(...) is deprecated in plain JavaScript React classes'
)
it 'supports this.context passed via getChildContext', ->
class Bar
@@ -404,9 +404,7 @@ describe('ReactES6Class', function() {
expect(() => instance.getDOMNode()).toThrow();
expect(() => instance.replaceState({})).toThrow();
expect(() => instance.isMounted()).toThrow();
expect(() => instance.setProps({name: 'bar'})).toThrow();
expect(() => instance.replaceProps({name: 'bar'})).toThrow();
expect(console.error.calls.length).toBe(5);
expect(console.error.calls.length).toBe(3);
expect(console.error.calls[0].args[0]).toContain(
'getDOMNode(...) is deprecated in plain JavaScript React classes. ' +
'Use React.findDOMNode(component) instead.'
@@ -417,12 +415,6 @@ describe('ReactES6Class', function() {
expect(console.error.calls[2].args[0]).toContain(
'isMounted(...) is deprecated in plain JavaScript React classes'
);
expect(console.error.calls[3].args[0]).toContain(
'setProps(...) is deprecated in plain JavaScript React classes'
);
expect(console.error.calls[4].args[0]).toContain(
'replaceProps(...) is deprecated in plain JavaScript React classes'
);
});
it('supports this.context passed via getChildContext', function() {
@@ -492,9 +492,7 @@ describe('ReactTypeScriptClass', function() {
expect(() => instance.getDOMNode()).toThrow();
expect(() => instance.replaceState({})).toThrow();
expect(() => instance.isMounted()).toThrow();
expect(() => instance.setProps({ name: 'bar' })).toThrow();
expect(() => instance.replaceProps({ name: 'bar' })).toThrow();
expect((<any>console.error).argsForCall.length).toBe(5);
expect((<any>console.error).argsForCall.length).toBe(3);
expect((<any>console.error).argsForCall[0][0]).toContain(
'getDOMNode(...) is deprecated in plain JavaScript React classes'
);
@@ -504,12 +502,6 @@ describe('ReactTypeScriptClass', function() {
expect((<any>console.error).argsForCall[2][0]).toContain(
'isMounted(...) is deprecated in plain JavaScript React classes'
);
expect((<any>console.error).argsForCall[3][0]).toContain(
'setProps(...) is deprecated in plain JavaScript React classes'
);
expect((<any>console.error).argsForCall[4][0]).toContain(
'replaceProps(...) is deprecated in plain JavaScript React classes'
);
});
it('supports this.context passed via getChildContext', function() {
@@ -30,7 +30,6 @@ var ReactDOMTextarea = require('ReactDOMTextarea');
var ReactMount = require('ReactMount');
var ReactMultiChild = require('ReactMultiChild');
var ReactPerf = require('ReactPerf');
var ReactUpdateQueue = require('ReactUpdateQueue');
var assign = require('Object.assign');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
@@ -130,44 +129,6 @@ function legacySetStateEtc() {
}
}
function legacySetProps(partialProps, callback) {
var component = this._reactInternalComponent;
if (__DEV__) {
warning(
false,
'ReactDOMComponent: Do not access .setProps() of a DOM node. ' +
'Instead, call React.render again at the top level.%s',
getDeclarationErrorAddendum(component)
);
}
if (!component) {
return;
}
ReactUpdateQueue.enqueueSetPropsInternal(component, partialProps);
if (callback) {
ReactUpdateQueue.enqueueCallbackInternal(component, callback);
}
}
function legacyReplaceProps(partialProps, callback) {
var component = this._reactInternalComponent;
if (__DEV__) {
warning(
false,
'ReactDOMComponent: Do not access .replaceProps() of a DOM node. ' +
'Instead, call React.render again at the top level.%s',
getDeclarationErrorAddendum(component)
);
}
if (!component) {
return;
}
ReactUpdateQueue.enqueueReplacePropsInternal(component, partialProps);
if (callback) {
ReactUpdateQueue.enqueueCallbackInternal(component, callback);
}
}
var styleMutationWarning = {};
function checkAndWarnForMutatedStyle(style1, style2, component) {
@@ -958,8 +919,6 @@ ReactDOMComponent.Mixin = {
node.setState = legacySetStateEtc;
node.replaceState = legacySetStateEtc;
node.forceUpdate = legacySetStateEtc;
node.setProps = legacySetProps;
node.replaceProps = legacyReplaceProps;
if (__DEV__) {
if (canDefineProperty) {
@@ -974,29 +974,6 @@ describe('ReactDOMComponent', function() {
expect(console.error.calls[4].args[0]).toContain('isMounted');
});
it('handles legacy setProps and replaceProps', function() {
spyOn(console, 'error');
var node = ReactTestUtils.renderIntoDocument(<div>rhinoceros</div>);
node.setProps({className: 'herbiverous'});
expect(node.className).toBe('herbiverous');
expect(node.textContent).toBe('rhinoceros');
node.replaceProps({className: 'invisible rhino'});
expect(node.className).toBe('invisible rhino');
expect(node.textContent).toBe('');
expect(console.error.calls.length).toBe(2);
expect(console.error.calls[0].args[0]).toBe(
'Warning: ReactDOMComponent: Do not access .setProps() of a DOM node. ' +
'Instead, call React.render again at the top level.'
);
expect(console.error.calls[1].args[0]).toBe(
'Warning: ReactDOMComponent: Do not access .replaceProps() of a DOM ' +
'node. Instead, call React.render again at the top level.'
);
});
it('does not touch ref-less nodes', function() {
var node = ReactTestUtils.renderIntoDocument(<div><span /></div>);
expect(typeof node.getDOMNode).toBe('function');
@@ -12,11 +12,9 @@
'use strict';
var ReactCurrentOwner = require('ReactCurrentOwner');
var ReactElement = require('ReactElement');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactUpdates = require('ReactUpdates');
var assign = require('Object.assign');
var invariant = require('invariant');
var warning = require('warning');
@@ -108,7 +106,7 @@ var ReactUpdateQueue = {
enqueueCallback: function(publicInstance, callback) {
invariant(
typeof callback === 'function',
'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
'enqueueCallback(...): You called ' +
'`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
'isn\'t callable.'
);
@@ -138,7 +136,7 @@ var ReactUpdateQueue = {
enqueueCallbackInternal: function(internalInstance, callback) {
invariant(
typeof callback === 'function',
'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
'enqueueCallback(...): You called ' +
'`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
'isn\'t callable.'
);
@@ -233,91 +231,6 @@ var ReactUpdateQueue = {
enqueueUpdate(internalInstance);
},
/**
* Sets a subset of the props.
*
* @param {ReactClass} publicInstance The instance that should rerender.
* @param {object} partialProps Subset of the next props.
* @internal
*/
enqueueSetProps: function(publicInstance, partialProps) {
var internalInstance = getInternalInstanceReadyForUpdate(
publicInstance,
'setProps'
);
if (!internalInstance) {
return;
}
ReactUpdateQueue.enqueueSetPropsInternal(internalInstance, partialProps);
},
enqueueSetPropsInternal: function(internalInstance, partialProps) {
var topLevelWrapper = internalInstance._topLevelWrapper;
invariant(
topLevelWrapper,
'setProps(...): You called `setProps` on a ' +
'component with a parent. This is an anti-pattern since props will ' +
'get reactively updated when rendered. Instead, change the owner\'s ' +
'`render` method to pass the correct value as props to the component ' +
'where it is created.'
);
// Merge with the pending element if it exists, otherwise with existing
// element props.
var wrapElement = topLevelWrapper._pendingElement ||
topLevelWrapper._currentElement;
var element = wrapElement.props;
var props = assign({}, element.props, partialProps);
topLevelWrapper._pendingElement = ReactElement.cloneAndReplaceProps(
wrapElement,
ReactElement.cloneAndReplaceProps(element, props)
);
enqueueUpdate(topLevelWrapper);
},
/**
* Replaces all of the props.
*
* @param {ReactClass} publicInstance The instance that should rerender.
* @param {object} props New props.
* @internal
*/
enqueueReplaceProps: function(publicInstance, props) {
var internalInstance = getInternalInstanceReadyForUpdate(
publicInstance,
'replaceProps'
);
if (!internalInstance) {
return;
}
ReactUpdateQueue.enqueueReplacePropsInternal(internalInstance, props);
},
enqueueReplacePropsInternal: function(internalInstance, props) {
var topLevelWrapper = internalInstance._topLevelWrapper;
invariant(
topLevelWrapper,
'replaceProps(...): You called `replaceProps` on a ' +
'component with a parent. This is an anti-pattern since props will ' +
'get reactively updated when rendered. Instead, change the owner\'s ' +
'`render` method to pass the correct value as props to the component ' +
'where it is created.'
);
// Merge with the pending element if it exists, otherwise with existing
// element props.
var wrapElement = topLevelWrapper._pendingElement ||
topLevelWrapper._currentElement;
var element = wrapElement.props;
topLevelWrapper._pendingElement = ReactElement.cloneAndReplaceProps(
wrapElement,
ReactElement.cloneAndReplaceProps(element, props)
);
enqueueUpdate(topLevelWrapper);
},
enqueueElementInternal: function(internalInstance, newElement) {
internalInstance._pendingElement = newElement;
enqueueUpdate(internalInstance);
@@ -199,7 +199,7 @@ function enqueueUpdate(component) {
// Various parts of our code (such as ReactCompositeComponent's
// _renderValidatedComponent) assume that calls to render aren't nested;
// verify that that's the case. (This is called by each top-level update
// function, like setProps, setState, forceUpdate, etc.; creation and
// function, like setState, forceUpdate, etc.; creation and
// destruction of top-level components is guarded in ReactMount.)
if (!batchingStrategy.isBatchingUpdates) {
@@ -442,46 +442,6 @@ describe('ReactComponentLifeCycle', function() {
expect(instance.state).toEqual(POST_WILL_UNMOUNT_STATE);
});
it('should throw when calling setProps() on an owned component', function() {
/**
* calls setProps in an componentDidMount.
*/
var Inner = React.createClass({
render: function() {
return <div />;
},
});
var PropsUpdaterInOnDOMReady = React.createClass({
componentDidMount: function() {
this.refs.theSimpleComponent.setProps({
className: this.props.valueToUseInOnDOMReady,
});
},
render: function() {
return (
<Inner
className={this.props.valueToUseInitially}
ref="theSimpleComponent"
/>
);
},
});
var instance =
<PropsUpdaterInOnDOMReady
valueToUseInitially="hello"
valueToUseInOnDOMReady="goodbye"
/>;
expect(function() {
instance = ReactTestUtils.renderIntoDocument(instance);
}).toThrow(
'Invariant Violation: setProps(...): You called `setProps` on a ' +
'component with a parent. This is an anti-pattern since props will get ' +
'reactively updated when rendered. Instead, change the owner\'s ' +
'`render` method to pass the correct value as props to the component ' +
'where it is created.'
);
});
it('should not throw when updating an auxiliary component', function() {
var Tooltip = React.createClass({
render: function() {
@@ -512,24 +472,18 @@ describe('ReactComponentLifeCycle', function() {
},
});
var instance = ReactTestUtils.renderIntoDocument(
<Component text="uno" tooltipText="one" />
var container = document.createElement('div');
React.render(
<Component text="uno" tooltipText="one" />,
container
);
// Since `instance` is a root component, we can set its props. This also
// makes Tooltip rerender the tooltip component, which shouldn't throw.
instance.setProps({text: 'dos', tooltipText: 'two'});
});
it('should not allow setProps() called on an unmounted element',
function() {
var PropsToUpdate = React.createClass({
render: function() {
return <div className={this.props.value} ref="theSimpleComponent" />;
},
});
var instance = <PropsToUpdate value="hello" />;
expect(instance.setProps).not.toBeDefined();
React.render(
<Component text="dos" tooltipText="two" />,
container
);
});
it('should allow state updates in componentDidMount', function() {
@@ -595,7 +549,7 @@ describe('ReactComponentLifeCycle', function() {
var container = document.createElement('div');
log = [];
var instance = React.render(<Outer x={17} />, container);
React.render(<Outer x={17} />, container);
expect(log).toEqual([
'outer componentWillMount',
'inner componentWillMount',
@@ -604,7 +558,7 @@ describe('ReactComponentLifeCycle', function() {
]);
log = [];
instance.setProps({x: 42});
React.render(<Outer x={42} />, container);
expect(log).toEqual([
'outer componentWillReceiveProps',
'outer shouldComponentUpdate',
@@ -138,10 +138,7 @@ describe('ReactCompositeComponent', function() {
it('should not cache old DOM nodes when switching constructors', function() {
var instance = <ChildUpdates renderAnchor={true} anchorClassOn={false}/>;
instance = ReactTestUtils.renderIntoDocument(instance);
instance.setProps({anchorClassOn: true}); // Warm any cache
instance.setProps({renderAnchor: false}); // Clear out the anchor
// rerender
instance.setProps({renderAnchor: true, anchorClassOn: false});
var anchor = instance.getAnchor();
var actualDOMAnchorNode = React.findDOMNode(anchor);
expect(actualDOMAnchorNode.className).toBe('');
@@ -399,72 +396,6 @@ describe('ReactCompositeComponent', function() {
expect(instance2.state.value).toBe(1);
});
it('should not allow `setProps` on unmounted components', function() {
var container = document.createElement('div');
document.body.appendChild(container);
var Component = React.createClass({
render: function() {
return <div />;
},
});
var instance = <Component />;
expect(instance.setProps).not.toBeDefined();
instance = React.render(instance, container);
expect(function() {
instance.setProps({value: 1});
}).not.toThrow();
expect(console.error.calls.length).toBe(0);
React.unmountComponentAtNode(container);
expect(function() {
instance.setProps({value: 2});
}).not.toThrow();
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toBe(
'Warning: setProps(...): Can only update a mounted or ' +
'mounting component. This usually means you called setProps() on an ' +
'unmounted component. This is a no-op. Please check the code for the ' +
'Component component.'
);
});
it('should only allow `setProps` on top-level components', function() {
var container = document.createElement('div');
document.body.appendChild(container);
var innerInstance;
var Inner = React.createClass({
render: function() {
return <div />;
},
});
var Component = React.createClass({
render: function() {
return <div><Inner ref="inner" /></div>;
},
componentDidMount: function() {
innerInstance = this.refs.inner;
},
});
React.render(<Component />, container);
expect(innerInstance).not.toBe(undefined);
expect(function() {
innerInstance.setProps({value: 1});
}).toThrow(
'Invariant Violation: setProps(...): You called `setProps` on a ' +
'component with a parent. This is an anti-pattern since props will get ' +
'reactively updated when rendered. Instead, change the owner\'s ' +
'`render` method to pass the correct value as props to the component ' +
'where it is created.'
);
});
it('should cleanup even if render() fatals', function() {
var BadComponent = React.createClass({
render: function() {
@@ -935,7 +866,8 @@ describe('ReactCompositeComponent', function() {
},
});
var comp = ReactTestUtils.renderIntoDocument(<Component flipped={false} />);
var container = document.createElement('div');
var comp = React.render(<Component flipped={false} />, container);
expect(React.findDOMNode(comp.refs.static0).textContent).toBe('A');
expect(React.findDOMNode(comp.refs.static1).textContent).toBe('B');
@@ -946,7 +878,7 @@ describe('ReactCompositeComponent', function() {
// When flipping the order, the refs should update even though the actual
// contents do not
comp.setProps({flipped: true});
React.render(<Component flipped={true} />, container);
expect(React.findDOMNode(comp.refs.static0).textContent).toBe('B');
expect(React.findDOMNode(comp.refs.static1).textContent).toBe('A');
@@ -138,8 +138,9 @@ describe('ReactCompositeComponent-state', function() {
this.peekAtState('initial-callback');
}
);
instance.setProps(
{nextColor: 'green'},
React.render(
<TestComponent stateListener={stateListener} nextColor="green" />,
container,
instance.peekAtCallback('setProps')
);
instance.setFavoriteColor('blue');
@@ -15,7 +15,6 @@ require('mock-modules');
var React = require('React');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactTestUtils = require('ReactTestUtils');
var ReactMount = require('ReactMount');
var mapObject = require('mapObject');
@@ -212,15 +211,20 @@ function verifyDomOrderingAccurate(parentInstance, statusDisplays) {
*/
function testPropsSequence(sequence) {
var i;
var parentInstance = ReactTestUtils.renderIntoDocument(
<FriendsStatusDisplay {...sequence[0]} />
var container = document.createElement('div');
var parentInstance = React.render(
<FriendsStatusDisplay {...sequence[0]} />,
container
);
var statusDisplays = parentInstance.getStatusDisplays();
var lastInternalStates = getInteralStateByUserName(statusDisplays);
verifyStatuses(statusDisplays, sequence[0]);
for (i = 1; i < sequence.length; i++) {
parentInstance.replaceProps(sequence[i]);
React.render(
<FriendsStatusDisplay {...sequence[i]} />,
container
);
statusDisplays = parentInstance.getStatusDisplays();
verifyStatuses(statusDisplays, sequence[i]);
verifyStatesPreserved(lastInternalStates, statusDisplays);
@@ -243,19 +247,27 @@ describe('ReactMultiChildReconcile', function() {
},
};
var parentInstance = ReactTestUtils.renderIntoDocument(
<FriendsStatusDisplay {...props} />
var container = document.createElement('div');
var parentInstance = React.render(
<FriendsStatusDisplay {...props} />,
container
);
var statusDisplays = parentInstance.getStatusDisplays();
var startingInternalState = statusDisplays.jcw.getInternalState();
// Now remove the child.
parentInstance.replaceProps({usernameToStatus: {} });
React.render(
<FriendsStatusDisplay />,
container
);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeFalsy();
// Now reset the props that cause there to be a child
parentInstance.replaceProps(props);
React.render(
<FriendsStatusDisplay {...props} />,
container
);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeTruthy();
expect(statusDisplays.jcw.getInternalState())
@@ -100,14 +100,12 @@ describe('ReactUpdates', function() {
expect(instance.state.y).toBe(0);
ReactUpdates.batchedUpdates(function() {
instance.setProps({x: 1});
instance.setState({y: 2});
expect(instance.props.x).toBe(0);
expect(instance.state.y).toBe(0);
expect(updateCount).toBe(0);
});
expect(instance.props.x).toBe(1);
expect(instance.state.y).toBe(2);
expect(updateCount).toBe(1);
});