mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Revert "Removed setProps and replaceProps (both previously deprecated)"
This reverts commit 721fe73541. We'll keep these with a warning for one more release.
This commit is contained in:
@@ -121,9 +121,9 @@ describe('ReactContextValidator', function() {
|
||||
},
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
React.render(<Parent foo="abc" />, container);
|
||||
React.render(<Parent foo="def" />, container);
|
||||
var instance = <Parent foo="abc" />;
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
instance.replaceProps({foo: 'def'});
|
||||
expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
|
||||
expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
|
||||
expect(actualComponentWillUpdate).toEqual({foo: 'def'});
|
||||
|
||||
@@ -728,6 +728,38 @@ 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,11 +112,19 @@ 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,6 +98,29 @@ 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,7 +346,9 @@ describe 'ReactCoffeeScriptClass', ->
|
||||
expect(-> instance.getDOMNode()).toThrow()
|
||||
expect(-> instance.replaceState {}).toThrow()
|
||||
expect(-> instance.isMounted()).toThrow()
|
||||
expect(console.error.calls.length).toBe 3
|
||||
expect(-> instance.setProps name: 'bar').toThrow()
|
||||
expect(-> instance.replaceProps name: 'bar').toThrow()
|
||||
expect(console.error.calls.length).toBe 5
|
||||
expect(console.error.calls[0].args[0]).toContain(
|
||||
'getDOMNode(...) is deprecated in plain JavaScript React classes'
|
||||
)
|
||||
@@ -356,6 +358,12 @@ 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,7 +404,9 @@ describe('ReactES6Class', function() {
|
||||
expect(() => instance.getDOMNode()).toThrow();
|
||||
expect(() => instance.replaceState({})).toThrow();
|
||||
expect(() => instance.isMounted()).toThrow();
|
||||
expect(console.error.calls.length).toBe(3);
|
||||
expect(() => instance.setProps({name: 'bar'})).toThrow();
|
||||
expect(() => instance.replaceProps({name: 'bar'})).toThrow();
|
||||
expect(console.error.calls.length).toBe(5);
|
||||
expect(console.error.calls[0].args[0]).toContain(
|
||||
'getDOMNode(...) is deprecated in plain JavaScript React classes. ' +
|
||||
'Use React.findDOMNode(component) instead.'
|
||||
@@ -415,6 +417,12 @@ 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,7 +492,9 @@ describe('ReactTypeScriptClass', function() {
|
||||
expect(() => instance.getDOMNode()).toThrow();
|
||||
expect(() => instance.replaceState({})).toThrow();
|
||||
expect(() => instance.isMounted()).toThrow();
|
||||
expect((<any>console.error).argsForCall.length).toBe(3);
|
||||
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[0][0]).toContain(
|
||||
'getDOMNode(...) is deprecated in plain JavaScript React classes'
|
||||
);
|
||||
@@ -502,6 +504,12 @@ 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,6 +30,7 @@ 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');
|
||||
@@ -129,6 +130,44 @@ 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) {
|
||||
@@ -919,6 +958,8 @@ ReactDOMComponent.Mixin = {
|
||||
node.setState = legacySetStateEtc;
|
||||
node.replaceState = legacySetStateEtc;
|
||||
node.forceUpdate = legacySetStateEtc;
|
||||
node.setProps = legacySetProps;
|
||||
node.replaceProps = legacyReplaceProps;
|
||||
|
||||
if (__DEV__) {
|
||||
if (canDefineProperty) {
|
||||
|
||||
@@ -974,6 +974,29 @@ 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,9 +12,11 @@
|
||||
'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');
|
||||
|
||||
@@ -106,7 +108,7 @@ var ReactUpdateQueue = {
|
||||
enqueueCallback: function(publicInstance, callback) {
|
||||
invariant(
|
||||
typeof callback === 'function',
|
||||
'enqueueCallback(...): You called ' +
|
||||
'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
|
||||
'`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
|
||||
'isn\'t callable.'
|
||||
);
|
||||
@@ -136,7 +138,7 @@ var ReactUpdateQueue = {
|
||||
enqueueCallbackInternal: function(internalInstance, callback) {
|
||||
invariant(
|
||||
typeof callback === 'function',
|
||||
'enqueueCallback(...): You called ' +
|
||||
'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
|
||||
'`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
|
||||
'isn\'t callable.'
|
||||
);
|
||||
@@ -231,6 +233,91 @@ 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 setState, forceUpdate, etc.; creation and
|
||||
// function, like setProps, setState, forceUpdate, etc.; creation and
|
||||
// destruction of top-level components is guarded in ReactMount.)
|
||||
|
||||
if (!batchingStrategy.isBatchingUpdates) {
|
||||
|
||||
@@ -442,6 +442,46 @@ 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() {
|
||||
@@ -472,18 +512,24 @@ describe('ReactComponentLifeCycle', function() {
|
||||
},
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
React.render(
|
||||
<Component text="uno" tooltipText="one" />,
|
||||
container
|
||||
var instance = ReactTestUtils.renderIntoDocument(
|
||||
<Component text="uno" tooltipText="one" />
|
||||
);
|
||||
|
||||
// Since `instance` is a root component, we can set its props. This also
|
||||
// makes Tooltip rerender the tooltip component, which shouldn't throw.
|
||||
React.render(
|
||||
<Component text="dos" tooltipText="two" />,
|
||||
container
|
||||
);
|
||||
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();
|
||||
});
|
||||
|
||||
it('should allow state updates in componentDidMount', function() {
|
||||
@@ -549,7 +595,7 @@ describe('ReactComponentLifeCycle', function() {
|
||||
|
||||
var container = document.createElement('div');
|
||||
log = [];
|
||||
React.render(<Outer x={17} />, container);
|
||||
var instance = React.render(<Outer x={17} />, container);
|
||||
expect(log).toEqual([
|
||||
'outer componentWillMount',
|
||||
'inner componentWillMount',
|
||||
@@ -558,7 +604,7 @@ describe('ReactComponentLifeCycle', function() {
|
||||
]);
|
||||
|
||||
log = [];
|
||||
React.render(<Outer x={42} />, container);
|
||||
instance.setProps({x: 42});
|
||||
expect(log).toEqual([
|
||||
'outer componentWillReceiveProps',
|
||||
'outer shouldComponentUpdate',
|
||||
|
||||
@@ -138,7 +138,10 @@ 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('');
|
||||
@@ -396,6 +399,72 @@ 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() {
|
||||
@@ -866,8 +935,7 @@ describe('ReactCompositeComponent', function() {
|
||||
},
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
var comp = React.render(<Component flipped={false} />, container);
|
||||
var comp = ReactTestUtils.renderIntoDocument(<Component flipped={false} />);
|
||||
expect(React.findDOMNode(comp.refs.static0).textContent).toBe('A');
|
||||
expect(React.findDOMNode(comp.refs.static1).textContent).toBe('B');
|
||||
|
||||
@@ -878,7 +946,7 @@ describe('ReactCompositeComponent', function() {
|
||||
|
||||
// When flipping the order, the refs should update even though the actual
|
||||
// contents do not
|
||||
React.render(<Component flipped={true} />, container);
|
||||
comp.setProps({flipped: true});
|
||||
expect(React.findDOMNode(comp.refs.static0).textContent).toBe('B');
|
||||
expect(React.findDOMNode(comp.refs.static1).textContent).toBe('A');
|
||||
|
||||
|
||||
@@ -138,9 +138,8 @@ describe('ReactCompositeComponent-state', function() {
|
||||
this.peekAtState('initial-callback');
|
||||
}
|
||||
);
|
||||
React.render(
|
||||
<TestComponent stateListener={stateListener} nextColor="green" />,
|
||||
container,
|
||||
instance.setProps(
|
||||
{nextColor: 'green'},
|
||||
instance.peekAtCallback('setProps')
|
||||
);
|
||||
instance.setFavoriteColor('blue');
|
||||
|
||||
@@ -15,6 +15,7 @@ require('mock-modules');
|
||||
|
||||
var React = require('React');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
var ReactMount = require('ReactMount');
|
||||
|
||||
var mapObject = require('mapObject');
|
||||
@@ -211,20 +212,15 @@ function verifyDomOrderingAccurate(parentInstance, statusDisplays) {
|
||||
*/
|
||||
function testPropsSequence(sequence) {
|
||||
var i;
|
||||
var container = document.createElement('div');
|
||||
var parentInstance = React.render(
|
||||
<FriendsStatusDisplay {...sequence[0]} />,
|
||||
container
|
||||
var parentInstance = ReactTestUtils.renderIntoDocument(
|
||||
<FriendsStatusDisplay {...sequence[0]} />
|
||||
);
|
||||
var statusDisplays = parentInstance.getStatusDisplays();
|
||||
var lastInternalStates = getInteralStateByUserName(statusDisplays);
|
||||
verifyStatuses(statusDisplays, sequence[0]);
|
||||
|
||||
for (i = 1; i < sequence.length; i++) {
|
||||
React.render(
|
||||
<FriendsStatusDisplay {...sequence[i]} />,
|
||||
container
|
||||
);
|
||||
parentInstance.replaceProps(sequence[i]);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
verifyStatuses(statusDisplays, sequence[i]);
|
||||
verifyStatesPreserved(lastInternalStates, statusDisplays);
|
||||
@@ -247,27 +243,19 @@ describe('ReactMultiChildReconcile', function() {
|
||||
},
|
||||
};
|
||||
|
||||
var container = document.createElement('div');
|
||||
var parentInstance = React.render(
|
||||
<FriendsStatusDisplay {...props} />,
|
||||
container
|
||||
var parentInstance = ReactTestUtils.renderIntoDocument(
|
||||
<FriendsStatusDisplay {...props} />
|
||||
);
|
||||
var statusDisplays = parentInstance.getStatusDisplays();
|
||||
var startingInternalState = statusDisplays.jcw.getInternalState();
|
||||
|
||||
// Now remove the child.
|
||||
React.render(
|
||||
<FriendsStatusDisplay />,
|
||||
container
|
||||
);
|
||||
parentInstance.replaceProps({usernameToStatus: {} });
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
expect(statusDisplays.jcw).toBeFalsy();
|
||||
|
||||
// Now reset the props that cause there to be a child
|
||||
React.render(
|
||||
<FriendsStatusDisplay {...props} />,
|
||||
container
|
||||
);
|
||||
parentInstance.replaceProps(props);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
expect(statusDisplays.jcw).toBeTruthy();
|
||||
expect(statusDisplays.jcw.getInternalState())
|
||||
|
||||
@@ -100,12 +100,14 @@ 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);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user