diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
index 027c536826..e2e5aee48b 100644
--- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
+++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
@@ -121,9 +121,9 @@ describe('ReactContextValidator', function() {
},
});
- var container = document.createElement('div');
- React.render(, container);
- React.render(, container);
+ var instance = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ instance.replaceProps({foo: 'def'});
expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
expect(actualComponentWillUpdate).toEqual({foo: 'def'});
diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js
index 717cec67a0..73ebdab706 100644
--- a/src/isomorphic/classic/class/ReactClass.js
+++ b/src/isomorphic/classic/class/ReactClass.js
@@ -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() {};
diff --git a/src/isomorphic/modern/class/ReactComponent.js b/src/isomorphic/modern/class/ReactComponent.js
index 80b3e655bf..ddf7bc14ef 100644
--- a/src/isomorphic/modern/class/ReactComponent.js
+++ b/src/isomorphic/modern/class/ReactComponent.js
@@ -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 {
diff --git a/src/isomorphic/modern/class/ReactNoopUpdateQueue.js b/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
index 42346794bc..69fc3ddb1b 100644
--- a/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
+++ b/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
@@ -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;
diff --git a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
index bcbf267547..2538cc39aa 100644
--- a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
+++ b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
@@ -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
diff --git a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
index 59cfe38ee4..0530c5bfb4 100644
--- a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
+++ b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
@@ -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() {
diff --git a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
index 476a77ebd3..a92eefda9a 100644
--- a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
+++ b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
@@ -492,7 +492,9 @@ describe('ReactTypeScriptClass', function() {
expect(() => instance.getDOMNode()).toThrow();
expect(() => instance.replaceState({})).toThrow();
expect(() => instance.isMounted()).toThrow();
- expect((console.error).argsForCall.length).toBe(3);
+ expect(() => instance.setProps({ name: 'bar' })).toThrow();
+ expect(() => instance.replaceProps({ name: 'bar' })).toThrow();
+ expect((console.error).argsForCall.length).toBe(5);
expect((console.error).argsForCall[0][0]).toContain(
'getDOMNode(...) is deprecated in plain JavaScript React classes'
);
@@ -502,6 +504,12 @@ describe('ReactTypeScriptClass', function() {
expect((console.error).argsForCall[2][0]).toContain(
'isMounted(...) is deprecated in plain JavaScript React classes'
);
+ expect((console.error).argsForCall[3][0]).toContain(
+ 'setProps(...) is deprecated in plain JavaScript React classes'
+ );
+ expect((console.error).argsForCall[4][0]).toContain(
+ 'replaceProps(...) is deprecated in plain JavaScript React classes'
+ );
});
it('supports this.context passed via getChildContext', function() {
diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js
index 4b5aa4f591..9f3af5cfc0 100644
--- a/src/renderers/dom/shared/ReactDOMComponent.js
+++ b/src/renderers/dom/shared/ReactDOMComponent.js
@@ -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) {
diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
index 55b0cb3229..d658a86237 100644
--- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
@@ -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(rhinoceros
);
+
+ 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(
);
expect(typeof node.getDOMNode).toBe('function');
diff --git a/src/renderers/shared/reconciler/ReactUpdateQueue.js b/src/renderers/shared/reconciler/ReactUpdateQueue.js
index b4adf37e34..d406fe20df 100644
--- a/src/renderers/shared/reconciler/ReactUpdateQueue.js
+++ b/src/renderers/shared/reconciler/ReactUpdateQueue.js
@@ -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);
diff --git a/src/renderers/shared/reconciler/ReactUpdates.js b/src/renderers/shared/reconciler/ReactUpdates.js
index 0a92535e8f..293645e0a8 100644
--- a/src/renderers/shared/reconciler/ReactUpdates.js
+++ b/src/renderers/shared/reconciler/ReactUpdates.js
@@ -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) {
diff --git a/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js
index 37f9d78da0..0a5a6b2993 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js
+++ b/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js
@@ -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 ;
+ },
+ });
+ var PropsUpdaterInOnDOMReady = React.createClass({
+ componentDidMount: function() {
+ this.refs.theSimpleComponent.setProps({
+ className: this.props.valueToUseInOnDOMReady,
+ });
+ },
+ render: function() {
+ return (
+
+ );
+ },
+ });
+ var instance =
+ ;
+ 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(
- ,
- container
+ var instance = ReactTestUtils.renderIntoDocument(
+
);
// 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(
- ,
- 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 ;
+ },
+ });
+ var instance = ;
+ 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(, container);
+ var instance = React.render(, container);
expect(log).toEqual([
'outer componentWillMount',
'inner componentWillMount',
@@ -558,7 +604,7 @@ describe('ReactComponentLifeCycle', function() {
]);
log = [];
- React.render(, container);
+ instance.setProps({x: 42});
expect(log).toEqual([
'outer componentWillReceiveProps',
'outer shouldComponentUpdate',
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
index cbae94cf97..e30858b648 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
+++ b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
@@ -138,7 +138,10 @@ describe('ReactCompositeComponent', function() {
it('should not cache old DOM nodes when switching constructors', function() {
var instance = ;
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 ;
+ },
+ });
+
+ var instance = ;
+ 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 ;
+ },
+ });
+ var Component = React.createClass({
+ render: function() {
+ return
;
+ },
+ componentDidMount: function() {
+ innerInstance = this.refs.inner;
+ },
+ });
+ React.render(, 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(, container);
+ var comp = ReactTestUtils.renderIntoDocument();
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(, container);
+ comp.setProps({flipped: true});
expect(React.findDOMNode(comp.refs.static0).textContent).toBe('B');
expect(React.findDOMNode(comp.refs.static1).textContent).toBe('A');
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js
index fda4de2cec..1547f47f33 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js
+++ b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js
@@ -138,9 +138,8 @@ describe('ReactCompositeComponent-state', function() {
this.peekAtState('initial-callback');
}
);
- React.render(
- ,
- container,
+ instance.setProps(
+ {nextColor: 'green'},
instance.peekAtCallback('setProps')
);
instance.setFavoriteColor('blue');
diff --git a/src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js b/src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
index 61faf39897..4e54164c13 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
+++ b/src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
@@ -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(
- ,
- container
+ var parentInstance = ReactTestUtils.renderIntoDocument(
+
);
var statusDisplays = parentInstance.getStatusDisplays();
var lastInternalStates = getInteralStateByUserName(statusDisplays);
verifyStatuses(statusDisplays, sequence[0]);
for (i = 1; i < sequence.length; i++) {
- React.render(
- ,
- 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(
- ,
- container
+ var parentInstance = ReactTestUtils.renderIntoDocument(
+
);
var statusDisplays = parentInstance.getStatusDisplays();
var startingInternalState = statusDisplays.jcw.getInternalState();
// Now remove the child.
- React.render(
- ,
- container
- );
+ parentInstance.replaceProps({usernameToStatus: {} });
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeFalsy();
// Now reset the props that cause there to be a child
- React.render(
- ,
- container
- );
+ parentInstance.replaceProps(props);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeTruthy();
expect(statusDisplays.jcw.getInternalState())
diff --git a/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js b/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js
index a2066d879a..10fa281ac2 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js
+++ b/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js
@@ -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);
});