diff --git a/mocks/ReactElementTestChild.js b/mocks/ReactElementTestChild.js
index f2c94d5dd6885..2e9d076933047 100644
--- a/mocks/ReactElementTestChild.js
+++ b/mocks/ReactElementTestChild.js
@@ -13,10 +13,10 @@
var React = require('React');
-var Child = React.createClass({
- render: function() {
+class Child extends React.Component {
+ render() {
return React.createElement('div');
- },
-});
+ }
+}
module.exports = Child;
diff --git a/mocks/ReactMockedComponentTestComponent.js b/mocks/ReactMockedComponentTestComponent.js
index 903006487374f..285265df14876 100644
--- a/mocks/ReactMockedComponentTestComponent.js
+++ b/mocks/ReactMockedComponentTestComponent.js
@@ -13,23 +13,18 @@
var React = require('React');
-var ReactMockedComponentTestComponent = React.createClass({
- getDefaultProps: function() {
- return {bar: 'baz'};
- },
+class ReactMockedComponentTestComponent extends React.Component {
+ state = {foo: 'bar'};
- getInitialState: function() {
- return {foo: 'bar'};
- },
-
- hasCustomMethod: function() {
+ hasCustomMethod() {
return true;
- },
+ }
- render: function() {
+ render() {
return ;
- },
+ }
-});
+}
+ReactMockedComponentTestComponent.defaultProps = {bar: 'baz'};
module.exports = ReactMockedComponentTestComponent;
diff --git a/package.json b/package.json
index e79c5278772ed..c4ea09e12a682 100644
--- a/package.json
+++ b/package.json
@@ -69,6 +69,7 @@
"merge-stream": "^1.0.0",
"object-assign": "^4.1.1",
"platform": "^1.1.0",
+ "react-create-class": "15.5.0-alpha.2",
"run-sequence": "^1.1.4",
"through2": "^2.0.0",
"tmp": "~0.0.28",
diff --git a/src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js b/src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js
deleted file mode 100644
index 2f5c7a36c040c..0000000000000
--- a/src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/**
- * Copyright 2015-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactComponentWithPureRenderMixin;
-var ReactTestUtils;
-
-describe('ReactComponentWithPureRenderMixin', () => {
-
- beforeEach(() => {
- React = require('React');
- ReactComponentWithPureRenderMixin =
- require('ReactComponentWithPureRenderMixin');
- ReactTestUtils = require('ReactTestUtils');
- });
-
- it('provides a default shouldComponentUpdate implementation', () => {
- var renderCalls = 0;
- class PlasticWrap extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- color: 'green',
- };
- }
-
- render() {
- return (
-
- );
- }
- }
-
- var Apple = React.createClass({
- mixins: [ReactComponentWithPureRenderMixin],
-
- getInitialState: function() {
- return {
- cut: false,
- slices: 1,
- };
- },
-
- cut: function() {
- this.setState({
- cut: true,
- slices: 10,
- });
- },
-
- eatSlice: function() {
- this.setState({
- slices: this.state.slices - 1,
- });
- },
-
- render: function() {
- renderCalls++;
- return
;
- },
- });
-
- var instance = ReactTestUtils.renderIntoDocument();
- expect(renderCalls).toBe(1);
-
- // Do not re-render based on props
- instance.setState({color: 'green'});
- expect(renderCalls).toBe(1);
-
- // Re-render based on props
- instance.setState({color: 'red'});
- expect(renderCalls).toBe(2);
-
- // Re-render base on state
- instance.refs.apple.cut();
- expect(renderCalls).toBe(3);
-
- // No re-render based on state
- instance.refs.apple.cut();
- expect(renderCalls).toBe(3);
-
- // Re-render based on state again
- instance.refs.apple.eatSlice();
- expect(renderCalls).toBe(4);
- });
-
- it('does not do a deep comparison', () => {
- function getInitialState() {
- return {
- foo: [1, 2, 3],
- bar: {a: 4, b: 5, c: 6},
- };
- }
-
- var renderCalls = 0;
- var initialSettings = getInitialState();
-
- var Component = React.createClass({
- mixins: [ReactComponentWithPureRenderMixin],
-
- getInitialState: function() {
- return initialSettings;
- },
-
- render: function() {
- renderCalls++;
- return ;
- },
- });
-
- var instance = ReactTestUtils.renderIntoDocument();
- expect(renderCalls).toBe(1);
-
- // Do not re-render if state is equal
- var settings = {
- foo: initialSettings.foo,
- bar: initialSettings.bar,
- };
- instance.setState(settings);
- expect(renderCalls).toBe(1);
-
- // Re-render because one field changed
- initialSettings.foo = [1, 2, 3];
- instance.setState(initialSettings);
- expect(renderCalls).toBe(2);
-
- // Re-render because the object changed
- instance.setState(getInitialState());
- expect(renderCalls).toBe(3);
- });
-
-});
diff --git a/src/addons/link/__tests__/LinkedStateMixin-test.js b/src/addons/link/__tests__/LinkedStateMixin-test.js
deleted file mode 100644
index 1d6fa18aff85f..0000000000000
--- a/src/addons/link/__tests__/LinkedStateMixin-test.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-
-describe('LinkedStateMixin', () => {
- var LinkedStateMixin;
- var React;
- var ReactTestUtils;
-
- beforeEach(() => {
- LinkedStateMixin = require('LinkedStateMixin');
- React = require('React');
- ReactTestUtils = require('ReactTestUtils');
- });
-
- it('should create a ReactLink for state', () => {
- var Component = React.createClass({
- mixins: [LinkedStateMixin],
-
- getInitialState: function() {
- return {value: 'initial value'};
- },
-
- render: function() {
- return value is {this.state.value};
- },
- });
- var component = ReactTestUtils.renderIntoDocument();
- var link = component.linkState('value');
- expect(component.state.value).toBe('initial value');
- expect(link.value).toBe('initial value');
- link.requestChange('new value');
- expect(component.state.value).toBe('new value');
- expect(component.linkState('value').value).toBe('new value');
- });
-});
diff --git a/src/addons/link/__tests__/ReactLinkPropTypes-test.js b/src/addons/link/__tests__/ReactLinkPropTypes-test.js
deleted file mode 100644
index 71406cf77d11b..0000000000000
--- a/src/addons/link/__tests__/ReactLinkPropTypes-test.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var emptyFunction = require('emptyFunction');
-var LinkPropTypes = require('ReactLink').PropTypes;
-var React = require('React');
-var ReactPropTypesSecret = require('ReactPropTypesSecret');
-
-var invalidMessage = 'Invalid prop `testProp` supplied to `testComponent`.';
-var requiredMessage = 'The prop `testProp` is marked as required in ' +
- '`testComponent`, but its value is `undefined`.';
-
-function typeCheckFail(declaration, value, message) {
- var props = {testProp: value};
- var error = declaration(
- props,
- 'testProp',
- 'testComponent',
- 'prop',
- null,
- ReactPropTypesSecret
- );
- expect(error instanceof Error).toBe(true);
- expect(error.message).toBe(message);
-}
-
-function typeCheckPass(declaration, value) {
- var props = {testProp: value};
- var error = declaration(
- props,
- 'testProp',
- 'testComponent',
- 'prop',
- null,
- ReactPropTypesSecret
- );
- expect(error).toBe(null);
-}
-
-describe('ReactLink', () => {
- it('should fail if the argument does not implement the Link API', () => {
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.any),
- {},
- 'The prop `testProp.value` is marked as required in `testComponent`, ' +
- 'but its value is `undefined`.'
- );
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.any),
- {value: 123},
- 'The prop `testProp.requestChange` is marked as required in ' +
- '`testComponent`, but its value is `undefined`.'
- );
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.any),
- {requestChange: emptyFunction},
- 'The prop `testProp.value` is marked as required in `testComponent`, ' +
- 'but its value is `undefined`.'
- );
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.any),
- {value: null, requestChange: null},
- 'The prop `testProp.value` is marked as required in `testComponent`, ' +
- 'but its value is `null`.'
- );
- });
-
- it('should allow valid links even if no type was specified', () => {
- typeCheckPass(
- LinkPropTypes.link(),
- {value: 42, requestChange: emptyFunction}
- );
- typeCheckPass(
- LinkPropTypes.link(),
- {value: {}, requestChange: emptyFunction}
- );
- });
-
- it('should allow no link to be passed at all', () => {
- typeCheckPass(
- LinkPropTypes.link(React.PropTypes.string),
- undefined
- );
- });
-
- it('should allow valid links with correct value format', () => {
- typeCheckPass(
- LinkPropTypes.link(React.PropTypes.any),
- {value: 42, requestChange: emptyFunction}
- );
- typeCheckPass(
- LinkPropTypes.link(React.PropTypes.number),
- {value: 42, requestChange: emptyFunction}
- );
- typeCheckPass(
- LinkPropTypes.link(React.PropTypes.node),
- {value: 42, requestChange: emptyFunction}
- );
- });
-
- it('should fail if the link`s value type does not match', () => {
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.string),
- {value: 123, requestChange: emptyFunction},
- 'Invalid prop `testProp.value` of type `number` supplied to `testComponent`,' +
- ' expected `string`.'
- );
- });
-
- it('should be implicitly optional and not warn without values', () => {
- typeCheckPass(LinkPropTypes.link(), null);
- typeCheckPass(LinkPropTypes.link(), undefined);
- typeCheckPass(LinkPropTypes.link(React.PropTypes.string), null);
- typeCheckPass(LinkPropTypes.link(React.PropTypes.string), undefined);
- });
-
- it('should warn for missing required values', () => {
- var specifiedButIsNullMsg = 'The prop `testProp` is marked as required ' +
- 'in `testComponent`, but its value is `null`.';
- typeCheckFail(LinkPropTypes.link().isRequired, null, specifiedButIsNullMsg);
- typeCheckFail(LinkPropTypes.link().isRequired, undefined, requiredMessage);
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.string).isRequired,
- null,
- specifiedButIsNullMsg
- );
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.string).isRequired,
- undefined,
- requiredMessage
- );
- });
-
- it('should be compatible with React.PropTypes.oneOfType', () => {
- typeCheckPass(
- React.PropTypes.oneOfType([LinkPropTypes.link(React.PropTypes.number)]),
- {value: 123, requestChange: emptyFunction}
- );
- typeCheckFail(
- React.PropTypes.oneOfType([LinkPropTypes.link(React.PropTypes.number)]),
- 123,
- invalidMessage
- );
- typeCheckPass(
- LinkPropTypes.link(React.PropTypes.oneOfType([React.PropTypes.number])),
- {value: 123, requestChange: emptyFunction}
- );
- typeCheckFail(
- LinkPropTypes.link(React.PropTypes.oneOfType([React.PropTypes.number])),
- {value: 'imastring', requestChange: emptyFunction},
- 'Invalid prop `testProp.value` supplied to `testComponent`.'
- );
- });
-});
diff --git a/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js
deleted file mode 100644
index 492b41e2e79a6..0000000000000
--- a/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js
+++ /dev/null
@@ -1,330 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var CSSCore = require('CSSCore');
-
-var React;
-var ReactDOM;
-var ReactCSSTransitionGroup;
-
-// Most of the real functionality is covered in other unit tests, this just
-// makes sure we're wired up correctly.
-describe('ReactCSSTransitionGroup', () => {
- var container;
-
- beforeEach(() => {
- jest.resetModuleRegistry();
- React = require('React');
- ReactDOM = require('ReactDOM');
- ReactCSSTransitionGroup = require('ReactCSSTransitionGroup');
-
- container = document.createElement('div');
- spyOn(console, 'error');
- });
-
- it('should warn if timeouts aren\'t specified', () => {
- ReactDOM.render(
-
-
- ,
- container
- );
-
- // Warning about the missing transitionLeaveTimeout prop
- expect(console.error.calls.count()).toBe(1);
- });
-
- it('should not warn if timeouts is zero', () => {
- ReactDOM.render(
-
-
- ,
- container
- );
-
- expect(console.error.calls.count()).toBe(0);
- });
-
- it('should clean-up silently after the timeout elapses', () => {
- var a = ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-
- setTimeout.mock.calls.length = 0;
-
- ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
- expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
- expect(ReactDOM.findDOMNode(a).childNodes[1].id).toBe('one');
-
- // For some reason jst is adding extra setTimeout()s and grunt test isn't,
- // so we need to do this disgusting hack.
- for (var i = 0; i < setTimeout.mock.calls.length; i++) {
- if (setTimeout.mock.calls[i][1] === 200) {
- setTimeout.mock.calls[i][0]();
- break;
- }
- }
-
- // No warnings
- expect(console.error.calls.count()).toBe(0);
-
- // The leaving child has been removed
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
- });
-
- it('should keep both sets of DOM nodes around', () => {
- var a = ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
- expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
- expect(ReactDOM.findDOMNode(a).childNodes[1].id).toBe('one');
- });
-
- it('should switch transitionLeave from false to true', () => {
- var a = ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
- expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('three');
- expect(ReactDOM.findDOMNode(a).childNodes[1].id).toBe('two');
- });
-
- it('should work with no children', () => {
- ReactDOM.render(
- ,
- container
- );
- });
-
- it('should work with a null child', () => {
- ReactDOM.render(
-
- {[null]}
- ,
- container
- );
- });
-
- it('should transition from one to null', () => {
- var a = ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- ReactDOM.render(
-
- {null}
- ,
- container
- );
- // (Here, we expect the original child to stick around but test that no
- // exception is thrown)
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('one');
- });
-
- it('should transition from false to one', () => {
- var a = ReactDOM.render(
-
- {false}
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(0);
- ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
- expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('one');
- });
-
- it('should use transition-type specific names when they\'re provided', () => {
- var customTransitionNames = {
- enter: 'custom-entering',
- leave: 'custom-leaving',
- };
-
- var a = ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-
- // Add an element
- ReactDOM.render(
-
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-
- var enteringNode = ReactDOM.findDOMNode(a).childNodes[1];
- expect(CSSCore.hasClass(enteringNode, 'custom-entering')).toBe(true);
-
- // Remove an element
- ReactDOM.render(
-
-
- ,
- container
- );
- expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-
- var leavingNode = ReactDOM.findDOMNode(a).childNodes[0];
- expect(CSSCore.hasClass(leavingNode, 'custom-leaving')).toBe(true);
- });
-
- it('should clear transition timeouts when unmounted', () => {
- class Component extends React.Component {
- render() {
- return (
-
- {this.props.children}
-
- );
- }
- }
-
- ReactDOM.render(, container);
- ReactDOM.render(, container);
-
- ReactDOM.unmountComponentAtNode(container);
-
- // Testing that no exception is thrown here, as the timeout has been cleared.
- jest.runAllTimers();
- });
-
- it('should handle unmounted elements properly', () => {
- class Child extends React.Component {
- render() {
- if (!this.props.show) {
- return null;
- }
- return ;
- }
- }
-
- class Component extends React.Component {
- state = { showChild: true };
-
- componentDidMount() {
- this.setState({ showChild: false });
- }
-
- render() {
- return (
-
-
-
- );
- }
- }
-
- ReactDOM.render(, container);
-
- // Testing that no exception is thrown here, as the timeout has been cleared.
- jest.runAllTimers();
- });
-});
diff --git a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactTransitionGroup-test.js
deleted file mode 100644
index 25e6dfdcd1f01..0000000000000
--- a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTransitionGroup;
-
-// Most of the real functionality is covered in other unit tests, this just
-// makes sure we're wired up correctly.
-describe('ReactTransitionGroup', () => {
- var container;
-
- beforeEach(() => {
- React = require('React');
- ReactDOM = require('ReactDOM');
- ReactTransitionGroup = require('ReactTransitionGroup');
-
- container = document.createElement('div');
- });
-
-
- it('should handle willEnter correctly', () => {
- var log = [];
-
- class Child extends React.Component {
- componentDidMount() {
- log.push('didMount');
- }
-
- componentWillAppear = (cb) => {
- log.push('willAppear');
- cb();
- };
-
- componentDidAppear = () => {
- log.push('didAppear');
- };
-
- componentWillEnter = (cb) => {
- log.push('willEnter');
- cb();
- };
-
- componentDidEnter = () => {
- log.push('didEnter');
- };
-
- componentWillLeave = (cb) => {
- log.push('willLeave');
- cb();
- };
-
- componentDidLeave = () => {
- log.push('didLeave');
- };
-
- componentWillUnmount() {
- log.push('willUnmount');
- }
-
- render() {
- return ;
- }
- }
-
- class Component extends React.Component {
- state = {count: 1};
-
- render() {
- var children = [];
- for (var i = 0; i < this.state.count; i++) {
- children.push();
- }
- return {children};
- }
- }
-
- var instance = ReactDOM.render(, container);
- expect(log).toEqual(['didMount', 'willAppear', 'didAppear']);
-
- log = [];
- instance.setState({count: 2}, function() {
- expect(log).toEqual(['didMount', 'willEnter', 'didEnter']);
-
- log = [];
- instance.setState({count: 1}, function() {
- expect(log).toEqual(['willLeave', 'didLeave', 'willUnmount']);
- });
- });
- });
-
- it('should handle enter/leave/enter/leave correctly', () => {
- var log = [];
- var willEnterCb;
-
- class Child extends React.Component {
- componentDidMount() {
- log.push('didMount');
- }
-
- componentWillEnter = (cb) => {
- log.push('willEnter');
- willEnterCb = cb;
- };
-
- componentDidEnter = () => {
- log.push('didEnter');
- };
-
- componentWillLeave = (cb) => {
- log.push('willLeave');
- cb();
- };
-
- componentDidLeave = () => {
- log.push('didLeave');
- };
-
- componentWillUnmount() {
- log.push('willUnmount');
- }
-
- render() {
- return ;
- }
- }
-
- class Component extends React.Component {
- state = {count: 1};
-
- render() {
- var children = [];
- for (var i = 0; i < this.state.count; i++) {
- children.push();
- }
- return {children};
- }
- }
-
- var instance = ReactDOM.render(, container);
- expect(log).toEqual(['didMount']);
- instance.setState({count: 2});
- expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
- for (var k = 0; k < 5; k++) {
- instance.setState({count: 2});
- expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
- instance.setState({count: 1});
- }
- // other animations are blocked until willEnterCb is called
- willEnterCb();
- expect(log).toEqual([
- 'didMount', 'didMount', 'willEnter',
- 'didEnter', 'willLeave', 'didLeave', 'willUnmount',
- ]);
- });
-
- it('should handle enter/leave/enter correctly', () => {
- var log = [];
- var willEnterCb;
-
- class Child extends React.Component {
- componentDidMount() {
- log.push('didMount');
- }
-
- componentWillEnter = (cb) => {
- log.push('willEnter');
- willEnterCb = cb;
- };
-
- componentDidEnter = () => {
- log.push('didEnter');
- };
-
- componentWillLeave = (cb) => {
- log.push('willLeave');
- cb();
- };
-
- componentDidLeave = () => {
- log.push('didLeave');
- };
-
- componentWillUnmount() {
- log.push('willUnmount');
- }
-
- render() {
- return ;
- }
- }
-
- class Component extends React.Component {
- state = {count: 1};
-
- render() {
- var children = [];
- for (var i = 0; i < this.state.count; i++) {
- children.push();
- }
- return {children};
- }
- }
-
- var instance = ReactDOM.render(, container);
- expect(log).toEqual(['didMount']);
- instance.setState({count: 2});
- expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
- for (var k = 0; k < 5; k++) {
- instance.setState({count: 1});
- expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
- instance.setState({count: 2});
- }
- willEnterCb();
- expect(log).toEqual([
- 'didMount', 'didMount', 'willEnter', 'didEnter',
- ]);
- });
-
- it('should handle entering/leaving several elements at once', () => {
- var log = [];
-
- class Child extends React.Component {
- componentDidMount() {
- log.push('didMount' + this.props.id);
- }
-
- componentWillEnter = (cb) => {
- log.push('willEnter' + this.props.id);
- cb();
- };
-
- componentDidEnter = () => {
- log.push('didEnter' + this.props.id);
- };
-
- componentWillLeave = (cb) => {
- log.push('willLeave' + this.props.id);
- cb();
- };
-
- componentDidLeave = () => {
- log.push('didLeave' + this.props.id);
- };
-
- componentWillUnmount() {
- log.push('willUnmount' + this.props.id);
- }
-
- render() {
- return ;
- }
- }
-
- class Component extends React.Component {
- state = {count: 1};
-
- render() {
- var children = [];
- for (var i = 0; i < this.state.count; i++) {
- children.push();
- }
- return {children};
- }
- }
-
- var instance = ReactDOM.render(, container);
- expect(log).toEqual(['didMount0']);
- log = [];
-
- instance.setState({count: 3});
- expect(log).toEqual([
- 'didMount1', 'didMount2', 'willEnter1', 'didEnter1',
- 'willEnter2', 'didEnter2',
- ]);
- log = [];
-
- instance.setState({count: 0});
- expect(log).toEqual([
- 'willLeave0', 'didLeave0', 'willLeave1', 'didLeave1',
- 'willLeave2', 'didLeave2', 'willUnmount0', 'willUnmount1', 'willUnmount2',
- ]);
- });
-
- it('should warn for duplicated keys', () => {
- spyOn(console, 'error');
-
- class Component extends React.Component {
- render() {
- var children = [, ];
- return {children};
- }
- }
-
- ReactDOM.render(, container);
-
- expect(console.error.calls.count()).toBe(2);
- expect(console.error.calls.argsFor(0)[0]).toBe(
- 'Warning: flattenChildren(...): ' +
- 'Encountered two children with the same key, `1`. ' +
- 'Child keys must be unique; when two children share a key, ' +
- 'only the first child will be used.'
- );
- expect(console.error.calls.argsFor(1)[0]).toBe(
- 'Warning: flattenChildren(...): ' +
- 'Encountered two children with the same key, `1`. ' +
- 'Child keys must be unique; when two children share a key, ' +
- 'only the first child will be used.'
- );
- });
-});
diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
index bda23752f7128..a02b9882252cf 100644
--- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
+++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
@@ -41,33 +41,31 @@ describe('ReactContextValidator', () => {
// ensure that this is not required for ES6 classes with Flow.
it('should filter out context not in contextTypes', () => {
- var Component = React.createClass({
- contextTypes: {
- foo: React.PropTypes.string,
- },
-
- render: function() {
+ class Component extends React.Component {
+ render() {
return ;
- },
- });
-
- var ComponentInFooBarContext = React.createClass({
- childContextTypes: {
- foo: React.PropTypes.string,
- bar: React.PropTypes.number,
- },
-
- getChildContext: function() {
+ }
+ }
+ Component.contextTypes = {
+ foo: React.PropTypes.string,
+ };
+
+ class ComponentInFooBarContext extends React.Component {
+ getChildContext() {
return {
foo: 'abc',
bar: 123,
};
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
+ }
+ }
+ ComponentInFooBarContext.childContextTypes = {
+ foo: React.PropTypes.string,
+ bar: React.PropTypes.number,
+ };
var instance = ReactTestUtils.renderIntoDocument();
reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
@@ -79,51 +77,50 @@ describe('ReactContextValidator', () => {
var actualComponentWillUpdate;
var actualComponentDidUpdate;
- var Parent = React.createClass({
- childContextTypes: {
- foo: React.PropTypes.string.isRequired,
- bar: React.PropTypes.string.isRequired,
- },
-
- getChildContext: function() {
+ class Parent extends React.Component {
+ getChildContext() {
return {
foo: this.props.foo,
bar: 'bar',
};
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
-
- var Component = React.createClass({
- contextTypes: {
- foo: React.PropTypes.string,
- },
-
- componentWillReceiveProps: function(nextProps, nextContext) {
+ }
+ }
+ Parent.childContextTypes = {
+ foo: React.PropTypes.string.isRequired,
+ bar: React.PropTypes.string.isRequired,
+ };
+
+ class Component extends React.Component {
+ componentWillReceiveProps(nextProps, nextContext) {
actualComponentWillReceiveProps = nextContext;
return true;
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState, nextContext) {
+ shouldComponentUpdate(nextProps, nextState, nextContext) {
actualShouldComponentUpdate = nextContext;
return true;
- },
+ }
- componentWillUpdate: function(nextProps, nextState, nextContext) {
+ componentWillUpdate(nextProps, nextState, nextContext) {
actualComponentWillUpdate = nextContext;
- },
+ }
- componentDidUpdate: function(prevProps, prevState, prevContext) {
+ componentDidUpdate(prevProps, prevState, prevContext) {
actualComponentDidUpdate = prevContext;
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
+ }
+ }
+ Component.contextTypes = {
+ foo: React.PropTypes.string,
+ };
+
var container = document.createElement('div');
ReactDOM.render(, container);
@@ -137,15 +134,14 @@ describe('ReactContextValidator', () => {
it('should check context types', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- contextTypes: {
- foo: React.PropTypes.string.isRequired,
- },
-
- render: function() {
+ class Component extends React.Component {
+ render() {
return ;
- },
- });
+ }
+ }
+ Component.contextTypes = {
+ foo: React.PropTypes.string.isRequired,
+ };
ReactTestUtils.renderIntoDocument();
@@ -157,21 +153,20 @@ describe('ReactContextValidator', () => {
' in Component (at **)'
);
- var ComponentInFooStringContext = React.createClass({
- childContextTypes: {
- foo: React.PropTypes.string,
- },
-
- getChildContext: function() {
+ class ComponentInFooStringContext extends React.Component {
+ getChildContext() {
return {
foo: this.props.fooValue,
};
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
+ }
+ }
+ ComponentInFooStringContext.childContextTypes = {
+ foo: React.PropTypes.string,
+ };
ReactTestUtils.renderIntoDocument(
@@ -180,21 +175,20 @@ describe('ReactContextValidator', () => {
// Previous call should not error
expect(console.error.calls.count()).toBe(1);
- var ComponentInFooNumberContext = React.createClass({
- childContextTypes: {
- foo: React.PropTypes.number,
- },
-
- getChildContext: function() {
+ class ComponentInFooNumberContext extends React.Component {
+ getChildContext() {
return {
foo: this.props.fooValue,
};
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
+ }
+ }
+ ComponentInFooNumberContext.childContextTypes = {
+ foo: React.PropTypes.number,
+ };
ReactTestUtils.renderIntoDocument();
@@ -211,20 +205,19 @@ describe('ReactContextValidator', () => {
it('should check child context types', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- childContextTypes: {
- foo: React.PropTypes.string.isRequired,
- bar: React.PropTypes.number,
- },
-
- getChildContext: function() {
+ class Component extends React.Component {
+ getChildContext() {
return this.props.testContext;
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
+ }
+ }
+ Component.childContextTypes = {
+ foo: React.PropTypes.string.isRequired,
+ bar: React.PropTypes.number,
+ };
ReactTestUtils.renderIntoDocument();
expect(console.error.calls.count()).toBe(1);
diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js
index a387299fcc536..7bc995f5506d3 100644
--- a/src/isomorphic/classic/class/ReactClass.js
+++ b/src/isomorphic/classic/class/ReactClass.js
@@ -13,877 +13,32 @@
var ReactComponent = require('ReactComponent');
var ReactElement = require('ReactElement');
-var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
-var emptyObject = require('emptyObject');
-var invariant = require('invariant');
var warning = require('warning');
-import type { ReactPropTypeLocations } from 'ReactPropTypeLocations';
+var factory = require('react-create-class/factory');
-var MIXINS_KEY = 'mixins';
-
-// Helper function to allow the creation of anonymous functions which do not
-// have .name set to the name of the variable being assigned to.
-function identity(fn) {
- return fn;
-}
-
-/**
- * Policies that describe methods in `ReactClassInterface`.
- */
-type SpecPolicy =
- /**
- * These methods may be defined only once by the class specification or mixin.
- */
- 'DEFINE_ONCE' |
- /**
- * These methods may be defined by both the class specification and mixins.
- * Subsequent definitions will be chained. These methods must return void.
- */
- 'DEFINE_MANY' |
- /**
- * These methods are overriding the base class.
- */
- 'OVERRIDE_BASE' |
- /**
- * These methods are similar to DEFINE_MANY, except we assume they return
- * objects. We try to merge the keys of the return values of all the mixed in
- * functions. If there is a key conflict we throw.
- */
- 'DEFINE_MANY_MERGED';
-
-
-var injectedMixins = [];
-
-/**
- * Composite components are higher-level components that compose other composite
- * or host components.
- *
- * To create a new type of `ReactClass`, pass a specification of
- * your new class to `React.createClass`. The only requirement of your class
- * specification is that you implement a `render` method.
- *
- * var MyComponent = React.createClass({
- * render: function() {
- * return Hello World
;
- * }
- * });
- *
- * The class specification supports a specific protocol of methods that have
- * special meaning (e.g. `render`). See `ReactClassInterface` for
- * more the comprehensive protocol. Any other properties and methods in the
- * class specification will be available on the prototype.
- *
- * @interface ReactClassInterface
- * @internal
- */
-var ReactClassInterface: {[key: string]: SpecPolicy} = {
-
- /**
- * An array of Mixin objects to include when defining your component.
- *
- * @type {array}
- * @optional
- */
- mixins: 'DEFINE_MANY',
-
- /**
- * An object containing properties and methods that should be defined on
- * the component's constructor instead of its prototype (static methods).
- *
- * @type {object}
- * @optional
- */
- statics: 'DEFINE_MANY',
-
- /**
- * Definition of prop types for this component.
- *
- * @type {object}
- * @optional
- */
- propTypes: 'DEFINE_MANY',
-
- /**
- * Definition of context types for this component.
- *
- * @type {object}
- * @optional
- */
- contextTypes: 'DEFINE_MANY',
-
- /**
- * Definition of context types this component sets for its children.
- *
- * @type {object}
- * @optional
- */
- childContextTypes: 'DEFINE_MANY',
-
- // ==== Definition methods ====
-
- /**
- * Invoked when the component is mounted. Values in the mapping will be set on
- * `this.props` if that prop is not specified (i.e. using an `in` check).
- *
- * This method is invoked before `getInitialState` and therefore cannot rely
- * on `this.state` or use `this.setState`.
- *
- * @return {object}
- * @optional
- */
- getDefaultProps: 'DEFINE_MANY_MERGED',
-
- /**
- * Invoked once before the component is mounted. The return value will be used
- * as the initial value of `this.state`.
- *
- * getInitialState: function() {
- * return {
- * isOn: false,
- * fooBaz: new BazFoo()
- * }
- * }
- *
- * @return {object}
- * @optional
- */
- getInitialState: 'DEFINE_MANY_MERGED',
-
- /**
- * @return {object}
- * @optional
- */
- getChildContext: 'DEFINE_MANY_MERGED',
-
- /**
- * Uses props from `this.props` and state from `this.state` to render the
- * structure of the component.
- *
- * No guarantees are made about when or how often this method is invoked, so
- * it must not have side effects.
- *
- * render: function() {
- * var name = this.props.name;
- * return Hello, {name}!
;
- * }
- *
- * @return {ReactComponent}
- * @nosideeffects
- * @required
- */
- render: 'DEFINE_ONCE',
-
-
-
- // ==== Delegate methods ====
-
- /**
- * Invoked when the component is initially created and about to be mounted.
- * This may have side effects, but any external subscriptions or data created
- * by this method must be cleaned up in `componentWillUnmount`.
- *
- * @optional
- */
- componentWillMount: 'DEFINE_MANY',
-
- /**
- * Invoked when the component has been mounted and has a DOM representation.
- * However, there is no guarantee that the DOM node is in the document.
- *
- * Use this as an opportunity to operate on the DOM when the component has
- * been mounted (initialized and rendered) for the first time.
- *
- * @param {DOMElement} rootNode DOM element representing the component.
- * @optional
- */
- componentDidMount: 'DEFINE_MANY',
-
- /**
- * Invoked before the component receives new props.
- *
- * Use this as an opportunity to react to a prop transition by updating the
- * state using `this.setState`. Current props are accessed via `this.props`.
- *
- * componentWillReceiveProps: function(nextProps, nextContext) {
- * this.setState({
- * likesIncreasing: nextProps.likeCount > this.props.likeCount
- * });
- * }
- *
- * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
- * transition may cause a state change, but the opposite is not true. If you
- * need it, you are probably looking for `componentWillUpdate`.
- *
- * @param {object} nextProps
- * @optional
- */
- componentWillReceiveProps: 'DEFINE_MANY',
-
- /**
- * Invoked while deciding if the component should be updated as a result of
- * receiving new props, state and/or context.
- *
- * Use this as an opportunity to `return false` when you're certain that the
- * transition to the new props/state/context will not require a component
- * update.
- *
- * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
- * return !equal(nextProps, this.props) ||
- * !equal(nextState, this.state) ||
- * !equal(nextContext, this.context);
- * }
- *
- * @param {object} nextProps
- * @param {?object} nextState
- * @param {?object} nextContext
- * @return {boolean} True if the component should update.
- * @optional
- */
- shouldComponentUpdate: 'DEFINE_ONCE',
-
- /**
- * Invoked when the component is about to update due to a transition from
- * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
- * and `nextContext`.
- *
- * Use this as an opportunity to perform preparation before an update occurs.
- *
- * NOTE: You **cannot** use `this.setState()` in this method.
- *
- * @param {object} nextProps
- * @param {?object} nextState
- * @param {?object} nextContext
- * @param {ReactReconcileTransaction} transaction
- * @optional
- */
- componentWillUpdate: 'DEFINE_MANY',
-
- /**
- * Invoked when the component's DOM representation has been updated.
- *
- * Use this as an opportunity to operate on the DOM when the component has
- * been updated.
- *
- * @param {object} prevProps
- * @param {?object} prevState
- * @param {?object} prevContext
- * @param {DOMElement} rootNode DOM element representing the component.
- * @optional
- */
- componentDidUpdate: 'DEFINE_MANY',
-
- /**
- * Invoked when the component is about to be removed from its parent and have
- * its DOM representation destroyed.
- *
- * Use this as an opportunity to deallocate any external resources.
- *
- * NOTE: There is no `componentDidUnmount` since your component will have been
- * destroyed by that point.
- *
- * @optional
- */
- componentWillUnmount: 'DEFINE_MANY',
-
-
-
- // ==== Advanced methods ====
-
- /**
- * Updates the component's currently mounted DOM representation.
- *
- * By default, this implements React's rendering and reconciliation algorithm.
- * Sophisticated clients may wish to override this.
- *
- * @param {ReactReconcileTransaction} transaction
- * @internal
- * @overridable
- */
- updateComponent: 'OVERRIDE_BASE',
-
-};
-
-/**
- * Mapping from class specification keys to special processing functions.
- *
- * Although these are declared like instance properties in the specification
- * when defining classes using `React.createClass`, they are actually static
- * and are accessible on the constructor instead of the prototype. Despite
- * being static, they must be defined outside of the "statics" key under
- * which all other static methods are defined.
- */
-var RESERVED_SPEC_KEYS = {
- displayName: function(Constructor, displayName) {
- Constructor.displayName = displayName;
- },
- mixins: function(Constructor, mixins) {
- if (mixins) {
- for (var i = 0; i < mixins.length; i++) {
- mixSpecIntoComponent(Constructor, mixins[i]);
- }
- }
- },
- childContextTypes: function(Constructor, childContextTypes) {
- if (__DEV__) {
- validateTypeDef(
- Constructor,
- childContextTypes,
- 'childContext'
- );
- }
- Constructor.childContextTypes = Object.assign(
- {},
- Constructor.childContextTypes,
- childContextTypes
- );
- },
- contextTypes: function(Constructor, contextTypes) {
- if (__DEV__) {
- validateTypeDef(
- Constructor,
- contextTypes,
- 'context'
- );
- }
- Constructor.contextTypes = Object.assign(
- {},
- Constructor.contextTypes,
- contextTypes
- );
- },
- /**
- * Special case getDefaultProps which should move into statics but requires
- * automatic merging.
- */
- getDefaultProps: function(Constructor, getDefaultProps) {
- if (Constructor.getDefaultProps) {
- Constructor.getDefaultProps = createMergedResultFunction(
- Constructor.getDefaultProps,
- getDefaultProps
- );
- } else {
- Constructor.getDefaultProps = getDefaultProps;
- }
- },
- propTypes: function(Constructor, propTypes) {
- if (__DEV__) {
- validateTypeDef(
- Constructor,
- propTypes,
- 'prop'
- );
- }
- Constructor.propTypes = Object.assign(
- {},
- Constructor.propTypes,
- propTypes
- );
- },
- statics: function(Constructor, statics) {
- mixStaticSpecIntoComponent(Constructor, statics);
- },
- autobind: function() {}, // noop
-};
-
-function validateTypeDef(
- Constructor,
- typeDef,
- location: ReactPropTypeLocations,
-) {
- for (var propName in typeDef) {
- if (typeDef.hasOwnProperty(propName)) {
- // use a warning instead of an invariant so components
- // don't show up in prod but only in __DEV__
- warning(
- typeof typeDef[propName] === 'function',
- '%s: %s type `%s` is invalid; it must be a function, usually from ' +
- 'React.PropTypes.',
- Constructor.displayName || 'ReactClass',
- ReactPropTypeLocationNames[location],
- propName
- );
- }
- }
-}
-
-function validateMethodOverride(isAlreadyDefined, name) {
- var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
- ReactClassInterface[name] :
- null;
-
- // Disallow overriding of base class methods unless explicitly allowed.
- if (ReactClassMixin.hasOwnProperty(name)) {
- invariant(
- specPolicy === 'OVERRIDE_BASE',
- 'ReactClassInterface: You are attempting to override ' +
- '`%s` from your class specification. Ensure that your method names ' +
- 'do not overlap with React methods.',
- name
- );
- }
-
- // Disallow defining methods more than once unless explicitly allowed.
- if (isAlreadyDefined) {
- invariant(
- specPolicy === 'DEFINE_MANY' ||
- specPolicy === 'DEFINE_MANY_MERGED',
- 'ReactClassInterface: You are attempting to define ' +
- '`%s` on your component more than once. This conflict may be due ' +
- 'to a mixin.',
- name
- );
- }
-}
-
-/**
- * Mixin helper which handles policy validation and reserved
- * specification keys when building React classes.
- */
-function mixSpecIntoComponent(Constructor, spec) {
- if (!spec) {
- if (__DEV__) {
- var typeofSpec = typeof spec;
- var isMixinValid = typeofSpec === 'object' && spec !== null;
-
- warning(
- isMixinValid,
- '%s: You\'re attempting to include a mixin that is either null ' +
- 'or not an object. Check the mixins included by the component, ' +
- 'as well as any mixins they include themselves. ' +
- 'Expected object but got %s.',
- Constructor.displayName || 'ReactClass',
- spec === null ? null : typeofSpec
- );
- }
-
- return;
- }
-
- invariant(
- typeof spec !== 'function',
- 'ReactClass: You\'re attempting to ' +
- 'use a component class or function as a mixin. Instead, just use a ' +
- 'regular object.'
- );
- invariant(
- !ReactElement.isValidElement(spec),
- 'ReactClass: You\'re attempting to ' +
- 'use a component as a mixin. Instead, just use a regular object.'
- );
-
- var proto = Constructor.prototype;
- var autoBindPairs = proto.__reactAutoBindPairs;
-
- // By handling mixins before any other properties, we ensure the same
- // chaining order is applied to methods with DEFINE_MANY policy, whether
- // mixins are listed before or after these methods in the spec.
- if (spec.hasOwnProperty(MIXINS_KEY)) {
- RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
- }
-
- for (var name in spec) {
- if (!spec.hasOwnProperty(name)) {
- continue;
- }
-
- if (name === MIXINS_KEY) {
- // We have already handled mixins in a special case above.
- continue;
- }
-
- var property = spec[name];
- var isAlreadyDefined = proto.hasOwnProperty(name);
- validateMethodOverride(isAlreadyDefined, name);
-
- if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
- RESERVED_SPEC_KEYS[name](Constructor, property);
- } else {
- // Setup methods on prototype:
- // The following member methods should not be automatically bound:
- // 1. Expected ReactClass methods (in the "interface").
- // 2. Overridden methods (that were mixed in).
- var isReactClassMethod =
- ReactClassInterface.hasOwnProperty(name);
- var isFunction = typeof property === 'function';
- var shouldAutoBind =
- isFunction &&
- !isReactClassMethod &&
- !isAlreadyDefined &&
- spec.autobind !== false;
-
- if (shouldAutoBind) {
- autoBindPairs.push(name, property);
- proto[name] = property;
- } else {
- if (isAlreadyDefined) {
- var specPolicy = ReactClassInterface[name];
-
- // These cases should already be caught by validateMethodOverride.
- invariant(
- isReactClassMethod && (
- specPolicy === 'DEFINE_MANY_MERGED' ||
- specPolicy === 'DEFINE_MANY'
- ),
- 'ReactClass: Unexpected spec policy %s for key %s ' +
- 'when mixing in component specs.',
- specPolicy,
- name
- );
-
- // For methods which are defined more than once, call the existing
- // methods before calling the new property, merging if appropriate.
- if (specPolicy === 'DEFINE_MANY_MERGED') {
- proto[name] = createMergedResultFunction(proto[name], property);
- } else if (specPolicy === 'DEFINE_MANY') {
- proto[name] = createChainedFunction(proto[name], property);
- }
- } else {
- proto[name] = property;
- if (__DEV__) {
- // Add verbose displayName to the function, which helps when looking
- // at profiling tools.
- if (typeof property === 'function' && spec.displayName) {
- proto[name].displayName = spec.displayName + '_' + name;
- }
- }
- }
- }
- }
- }
-}
-
-function mixStaticSpecIntoComponent(Constructor, statics) {
- if (!statics) {
- return;
- }
- for (var name in statics) {
- var property = statics[name];
- if (!statics.hasOwnProperty(name)) {
- continue;
- }
-
- var isReserved = name in RESERVED_SPEC_KEYS;
- invariant(
- !isReserved,
- 'ReactClass: You are attempting to define a reserved ' +
- 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
- 'as an instance property instead; it will still be accessible on the ' +
- 'constructor.',
- name
- );
-
- var isInherited = name in Constructor;
- invariant(
- !isInherited,
- 'ReactClass: You are attempting to define ' +
- '`%s` on your component more than once. This conflict may be ' +
- 'due to a mixin.',
- name
- );
- Constructor[name] = property;
- }
-}
-
-/**
- * Merge two objects, but throw if both contain the same key.
- *
- * @param {object} one The first object, which is mutated.
- * @param {object} two The second object
- * @return {object} one after it has been mutated to contain everything in two.
- */
-function mergeIntoWithNoDuplicateKeys(one, two) {
- invariant(
- one && two && typeof one === 'object' && typeof two === 'object',
- 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
- );
-
- for (var key in two) {
- if (two.hasOwnProperty(key)) {
- invariant(
- one[key] === undefined,
- 'mergeIntoWithNoDuplicateKeys(): ' +
- 'Tried to merge two objects with the same key: `%s`. This conflict ' +
- 'may be due to a mixin; in particular, this may be caused by two ' +
- 'getInitialState() or getDefaultProps() methods returning objects ' +
- 'with clashing keys.',
- key
- );
- one[key] = two[key];
- }
- }
- return one;
-}
-
-/**
- * Creates a function that invokes two functions and merges their return values.
- *
- * @param {function} one Function to invoke first.
- * @param {function} two Function to invoke second.
- * @return {function} Function that invokes the two argument functions.
- * @private
- */
-function createMergedResultFunction(one, two) {
- return function mergedResult() {
- var a = one.apply(this, arguments);
- var b = two.apply(this, arguments);
- if (a == null) {
- return b;
- } else if (b == null) {
- return a;
- }
- var c = {};
- mergeIntoWithNoDuplicateKeys(c, a);
- mergeIntoWithNoDuplicateKeys(c, b);
- return c;
- };
-}
-
-/**
- * Creates a function that invokes two functions and ignores their return vales.
- *
- * @param {function} one Function to invoke first.
- * @param {function} two Function to invoke second.
- * @return {function} Function that invokes the two argument functions.
- * @private
- */
-function createChainedFunction(one, two) {
- return function chainedFunction() {
- one.apply(this, arguments);
- two.apply(this, arguments);
- };
-}
-
-/**
- * Binds a method to the component.
- *
- * @param {object} component Component whose method is going to be bound.
- * @param {function} method Method to be bound.
- * @return {function} The bound method.
- */
-function bindAutoBindMethod(component, method) {
- var boundMethod = method.bind(component);
- if (__DEV__) {
- boundMethod.__reactBoundContext = component;
- boundMethod.__reactBoundMethod = method;
- boundMethod.__reactBoundArguments = null;
- var componentName = component.constructor.displayName;
- var _bind = boundMethod.bind;
- boundMethod.bind = function(newThis, ...args) {
- // User is trying to bind() an autobound method; we effectively will
- // ignore the value of "this" that the user is trying to use, so
- // let's warn.
- if (newThis !== component && newThis !== null) {
- warning(
- false,
- 'bind(): React component methods may only be bound to the ' +
- 'component instance. See %s',
- componentName
- );
- } else if (!args.length) {
- warning(
- false,
- 'bind(): You are binding a component method to the component. ' +
- 'React does this for you automatically in a high-performance ' +
- 'way, so you can safely remove this call. See %s',
- componentName
- );
- return boundMethod;
- }
- var reboundMethod = _bind.apply(boundMethod, arguments);
- reboundMethod.__reactBoundContext = component;
- reboundMethod.__reactBoundMethod = method;
- reboundMethod.__reactBoundArguments = args;
- return reboundMethod;
- };
- }
- return boundMethod;
-}
-
-/**
- * Binds all auto-bound methods in a component.
- *
- * @param {object} component Component whose method is going to be bound.
- */
-function bindAutoBindMethods(component) {
- var pairs = component.__reactAutoBindPairs;
- for (var i = 0; i < pairs.length; i += 2) {
- var autoBindKey = pairs[i];
- var method = pairs[i + 1];
- component[autoBindKey] = bindAutoBindMethod(
- component,
- method
- );
- }
-}
-
-/**
- * Add more to the ReactClass base class. These are all legacy features and
- * therefore not already part of the modern ReactComponent.
- */
-var ReactClassMixin = {
-
- /**
- * TODO: This will be deprecated because state should always keep a consistent
- * type signature and the only use case for this, is to avoid that.
- */
- replaceState: function(newState, callback) {
- this.updater.enqueueReplaceState(this, newState);
- if (callback) {
- this.updater.enqueueCallback(this, callback, 'replaceState');
- }
- },
-
- /**
- * Checks whether or not this composite component is mounted.
- * @return {boolean} True if mounted, false otherwise.
- * @protected
- * @final
- */
- isMounted: function() {
- return this.updater.isMounted(this);
- },
-};
-
-var ReactClassComponent = function() {};
-Object.assign(
- ReactClassComponent.prototype,
- ReactComponent.prototype,
- ReactClassMixin
+var createClass = factory(
+ ReactComponent,
+ ReactElement.isValidElement,
+ ReactNoopUpdateQueue
);
-/**
- * Module for creating composite components.
- *
- * @class ReactClass
- */
-var ReactClass = {
-
- /**
- * Creates a composite component class given a class specification.
- * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass
- *
- * @param {object} spec Class specification (which must define `render`).
- * @return {function} Component constructor function.
- * @public
- */
- createClass: function(spec) {
- // To keep our warnings more understandable, we'll use a little hack here to
- // ensure that Constructor.name !== 'Constructor'. This makes sure we don't
- // unnecessarily identify a class without displayName as 'Constructor'.
- var Constructor = identity(function(props, context, updater) {
- // This constructor gets overridden by mocks. The argument is used
- // by mocks to assert on what gets mounted.
-
- if (__DEV__) {
- warning(
- this instanceof Constructor,
- 'Something is calling a React component directly. Use a factory or ' +
- 'JSX instead. See: https://fb.me/react-legacyfactory'
- );
- }
-
- // Wire up auto-binding
- if (this.__reactAutoBindPairs.length) {
- bindAutoBindMethods(this);
- }
-
- this.props = props;
- this.context = context;
- this.refs = emptyObject;
- this.updater = updater || ReactNoopUpdateQueue;
-
- this.state = null;
-
- // ReactClasses doesn't have constructors. Instead, they use the
- // getInitialState and componentWillMount methods for initialization.
-
- var initialState = this.getInitialState ? this.getInitialState() : null;
- if (__DEV__) {
- // We allow auto-mocks to proceed as if they're returning null.
- if (initialState === undefined &&
- this.getInitialState._isMockFunction) {
- // This is probably bad practice. Consider warning here and
- // deprecating this convenience.
- initialState = null;
- }
- }
- invariant(
- typeof initialState === 'object' && !Array.isArray(initialState),
- '%s.getInitialState(): must return an object or null',
- Constructor.displayName || 'ReactCompositeComponent'
- );
-
- this.state = initialState;
- });
- Constructor.prototype = new ReactClassComponent();
- Constructor.prototype.constructor = Constructor;
- Constructor.prototype.__reactAutoBindPairs = [];
-
- injectedMixins.forEach(
- mixSpecIntoComponent.bind(null, Constructor)
- );
-
- mixSpecIntoComponent(Constructor, spec);
-
- // Initialize the defaultProps property after all mixins have been merged.
- if (Constructor.getDefaultProps) {
- Constructor.defaultProps = Constructor.getDefaultProps();
- }
-
- if (__DEV__) {
- // This is a tag to indicate that the use of these method names is ok,
- // since it's used with createClass. If it's not, then it's likely a
- // mistake so we'll warn you to use the static property, property
- // initializer or constructor respectively.
- if (Constructor.getDefaultProps) {
- Constructor.getDefaultProps.isReactClassApproved = {};
- }
- if (Constructor.prototype.getInitialState) {
- Constructor.prototype.getInitialState.isReactClassApproved = {};
- }
- }
-
- invariant(
- Constructor.prototype.render,
- 'createClass(...): Class specification must implement a `render` method.'
- );
+let didWarnDeprecated = false;
+module.exports = {
+ createClass(...args) {
if (__DEV__) {
warning(
- !Constructor.prototype.componentShouldUpdate,
- '%s has a method called ' +
- 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
- 'The name is phrased as a question because the function is ' +
- 'expected to return a value.',
- spec.displayName || 'A component'
- );
- warning(
- !Constructor.prototype.componentWillRecieveProps,
- '%s has a method called ' +
- 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
- spec.displayName || 'A component'
+ didWarnDeprecated,
+ 'React.createClass is deprecated and will be removed in version 16. ' +
+ 'Use plain JavaScript classes instead. If you\'re not yet ready to ' +
+ 'migrate, react-create-class is available on npm as a ' +
+ 'drop-in replacement.'
);
+ didWarnDeprecated = true;
}
-
- // Reduce time spent doing lookups by setting these on the prototype.
- for (var methodName in ReactClassInterface) {
- if (!Constructor.prototype[methodName]) {
- Constructor.prototype[methodName] = null;
- }
- }
-
- return Constructor;
+ return createClass(...args);
},
-
- injection: {
- injectMixin: function(mixin) {
- injectedMixins.push(mixin);
- },
- },
-
};
-
-module.exports = ReactClass;
diff --git a/src/isomorphic/classic/class/__tests__/ReactBind-test.js b/src/isomorphic/classic/class/__tests__/ReactBind-test.js
deleted file mode 100644
index a5b612eba3a71..0000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactBind-test.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-/*global global:true*/
-'use strict';
-
-var React = require('React');
-var ReactTestUtils = require('ReactTestUtils');
-var reactComponentExpect = require('reactComponentExpect');
-
-// TODO: Test render and all stock methods.
-describe('autobinding', () => {
-
- it('Holds reference to instance', () => {
-
- var mouseDidEnter = jest.fn();
- var mouseDidLeave = jest.fn();
- var mouseDidClick = jest.fn();
-
- var TestBindComponent = React.createClass({
- getInitialState: function() {
- return {something: 'hi'};
- },
- onMouseEnter: mouseDidEnter,
- onMouseLeave: mouseDidLeave,
- onClick: mouseDidClick,
-
- // auto binding only occurs on top level functions in class defs.
- badIdeas: {
- badBind: function() {
- void this.state.something;
- },
- },
-
- render: function() {
- return (
-
- );
- },
- });
-
- var instance1 = ;
- var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
- var rendered1 = reactComponentExpect(mountedInstance1)
- .expectRenderedChild()
- .instance();
-
- var instance2 = ;
- var mountedInstance2 = ReactTestUtils.renderIntoDocument(instance2);
- var rendered2 = reactComponentExpect(mountedInstance2)
- .expectRenderedChild()
- .instance();
-
- expect(function() {
- var badIdea = instance1.badIdeas.badBind;
- badIdea();
- }).toThrow();
-
- expect(mountedInstance1.onClick).not.toBe(mountedInstance2.onClick);
-
- ReactTestUtils.Simulate.click(rendered1);
- expect(mouseDidClick.mock.instances.length).toBe(1);
- expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-
- ReactTestUtils.Simulate.click(rendered2);
- expect(mouseDidClick.mock.instances.length).toBe(2);
- expect(mouseDidClick.mock.instances[1]).toBe(mountedInstance2);
-
- ReactTestUtils.Simulate.mouseOver(rendered1);
- expect(mouseDidEnter.mock.instances.length).toBe(1);
- expect(mouseDidEnter.mock.instances[0]).toBe(mountedInstance1);
-
- ReactTestUtils.Simulate.mouseOver(rendered2);
- expect(mouseDidEnter.mock.instances.length).toBe(2);
- expect(mouseDidEnter.mock.instances[1]).toBe(mountedInstance2);
-
- ReactTestUtils.Simulate.mouseOut(rendered1);
- expect(mouseDidLeave.mock.instances.length).toBe(1);
- expect(mouseDidLeave.mock.instances[0]).toBe(mountedInstance1);
-
- ReactTestUtils.Simulate.mouseOut(rendered2);
- expect(mouseDidLeave.mock.instances.length).toBe(2);
- expect(mouseDidLeave.mock.instances[1]).toBe(mountedInstance2);
- });
-
- it('works with mixins', () => {
- var mouseDidClick = jest.fn();
-
- var TestMixin = {
- onClick: mouseDidClick,
- };
-
- var TestBindComponent = React.createClass({
- mixins: [TestMixin],
-
- render: function() {
- return ;
- },
- });
-
- var instance1 = ;
- var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
- var rendered1 = reactComponentExpect(mountedInstance1)
- .expectRenderedChild()
- .instance();
-
- ReactTestUtils.Simulate.click(rendered1);
- expect(mouseDidClick.mock.instances.length).toBe(1);
- expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
- });
-
- it('warns if you try to bind to this', () => {
- spyOn(console, 'error');
-
- var TestBindComponent = React.createClass({
- handleClick: function() { },
- render: function() {
- return ;
- },
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.argsFor(0)[0]).toBe(
- 'Warning: bind(): You are binding a component method to the component. ' +
- 'React does this for you automatically in a high-performance ' +
- 'way, so you can safely remove this call. See TestBindComponent'
- );
- });
-
- it('does not warn if you pass an auto-bound method to setState', () => {
- spyOn(console, 'error');
-
- var TestBindComponent = React.createClass({
- getInitialState: function() {
- return {foo: 1};
- },
- componentDidMount: function() {
- this.setState({foo: 2}, this.handleUpdate);
- },
- handleUpdate: function() {
-
- },
- render: function() {
- return ;
- },
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.error.calls.count()).toBe(0);
- });
-
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js b/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js
deleted file mode 100644
index 635b594dee276..0000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js
+++ /dev/null
@@ -1,233 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-/*global global:true*/
-'use strict';
-
-var React = require('React');
-var ReactTestUtils = require('ReactTestUtils');
-var reactComponentExpect = require('reactComponentExpect');
-
-// TODO: Test render and all stock methods.
-describe('autobind optout', () => {
-
- it('should work with manual binding', () => {
-
- var mouseDidEnter = jest.fn();
- var mouseDidLeave = jest.fn();
- var mouseDidClick = jest.fn();
-
- var TestBindComponent = React.createClass({
- autobind: false,
- getInitialState: function() {
- return {something: 'hi'};
- },
- onMouseEnter: mouseDidEnter,
- onMouseLeave: mouseDidLeave,
- onClick: mouseDidClick,
-
- render: function() {
- return (
-
- );
- },
- });
-
- var instance1 = ;
- var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
- var rendered1 = reactComponentExpect(mountedInstance1)
- .expectRenderedChild()
- .instance();
-
- var instance2 = ;
- var mountedInstance2 = ReactTestUtils.renderIntoDocument(instance2);
- var rendered2 = reactComponentExpect(mountedInstance2)
- .expectRenderedChild()
- .instance();
-
- ReactTestUtils.Simulate.click(rendered1);
- expect(mouseDidClick.mock.instances.length).toBe(1);
- expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-
- ReactTestUtils.Simulate.click(rendered2);
- expect(mouseDidClick.mock.instances.length).toBe(2);
- expect(mouseDidClick.mock.instances[1]).toBe(mountedInstance2);
-
- ReactTestUtils.Simulate.mouseOver(rendered1);
- expect(mouseDidEnter.mock.instances.length).toBe(1);
- expect(mouseDidEnter.mock.instances[0]).toBe(mountedInstance1);
-
- ReactTestUtils.Simulate.mouseOver(rendered2);
- expect(mouseDidEnter.mock.instances.length).toBe(2);
- expect(mouseDidEnter.mock.instances[1]).toBe(mountedInstance2);
-
- ReactTestUtils.Simulate.mouseOut(rendered1);
- expect(mouseDidLeave.mock.instances.length).toBe(1);
- expect(mouseDidLeave.mock.instances[0]).toBe(mountedInstance1);
-
- ReactTestUtils.Simulate.mouseOut(rendered2);
- expect(mouseDidLeave.mock.instances.length).toBe(2);
- expect(mouseDidLeave.mock.instances[1]).toBe(mountedInstance2);
- });
-
- it('should not hold reference to instance', () => {
- var mouseDidClick = function() {
- void this.state.something;
- };
-
- var TestBindComponent = React.createClass({
- autobind: false,
- getInitialState: function() {
- return {something: 'hi'};
- },
- onClick: mouseDidClick,
-
- // auto binding only occurs on top level functions in class defs.
- badIdeas: {
- badBind: function() {
- void this.state.something;
- },
- },
-
- render: function() {
- return (
-
- );
- },
- });
-
- var instance1 = ;
- var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
- var rendered1 = reactComponentExpect(mountedInstance1)
- .expectRenderedChild()
- .instance();
-
- var instance2 = ;
- var mountedInstance2 = ReactTestUtils.renderIntoDocument(instance2);
- var rendered2 = reactComponentExpect(mountedInstance2)
- .expectRenderedChild()
- .instance();
-
- expect(function() {
- var badIdea = instance1.badIdeas.badBind;
- badIdea();
- }).toThrow();
-
- expect(mountedInstance1.onClick).toBe(mountedInstance2.onClick);
-
- expect(function() {
- ReactTestUtils.Simulate.click(rendered1);
- }).toThrow();
-
- expect(function() {
- ReactTestUtils.Simulate.click(rendered2);
- }).toThrow();
- });
-
- it('works with mixins that have not opted out of autobinding', () => {
- var mouseDidClick = jest.fn();
-
- var TestMixin = {
- onClick: mouseDidClick,
- };
-
- var TestBindComponent = React.createClass({
- mixins: [TestMixin],
-
- render: function() {
- return ;
- },
- });
-
- var instance1 = ;
- var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
- var rendered1 = reactComponentExpect(mountedInstance1)
- .expectRenderedChild()
- .instance();
-
- ReactTestUtils.Simulate.click(rendered1);
- expect(mouseDidClick.mock.instances.length).toBe(1);
- expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
- });
-
- it('works with mixins that have opted out of autobinding', () => {
- var mouseDidClick = jest.fn();
-
- var TestMixin = {
- autobind: false,
- onClick: mouseDidClick,
- };
-
- var TestBindComponent = React.createClass({
- mixins: [TestMixin],
-
- render: function() {
- return ;
- },
- });
-
- var instance1 = ;
- var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
- var rendered1 = reactComponentExpect(mountedInstance1)
- .expectRenderedChild()
- .instance();
-
- ReactTestUtils.Simulate.click(rendered1);
- expect(mouseDidClick.mock.instances.length).toBe(1);
- expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
- });
-
- it('does not warn if you try to bind to this', () => {
- spyOn(console, 'error');
-
- var TestBindComponent = React.createClass({
- autobind: false,
- handleClick: function() { },
- render: function() {
- return ;
- },
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.error.calls.count()).toBe(0);
- });
-
- it('does not warn if you pass an manually bound method to setState', () => {
- spyOn(console, 'error');
-
- var TestBindComponent = React.createClass({
- autobind: false,
- getInitialState: function() {
- return {foo: 1};
- },
- componentDidMount: function() {
- this.setState({foo: 2}, this.handleUpdate.bind(this));
- },
- handleUpdate: function() {
-
- },
- render: function() {
- return ;
- },
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.error.calls.count()).toBe(0);
- });
-
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactClass-test.js b/src/isomorphic/classic/class/__tests__/ReactClass-test.js
index e56d3913ba8d3..e992af7429b45 100644
--- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js
+++ b/src/isomorphic/classic/class/__tests__/ReactClass-test.js
@@ -23,6 +23,26 @@ describe('ReactClass-spec', () => {
ReactTestUtils = require('ReactTestUtils');
});
+ it('should warn on first call to React.createClass', () => {
+ spyOn(console, 'error');
+ const spec = {
+ render() {
+ return ;
+ },
+ };
+ React.createClass(spec);
+ React.createClass(spec);
+ expect(console.error.calls.count()).toEqual(1);
+ expect(console.error.calls.count()).toEqual(1);
+ expect(console.error.calls.argsFor(0)[0]).toBe(
+ 'Warning: React.createClass is deprecated and will be removed in ' +
+ 'version 16. Use plain JavaScript classes instead. If you\'re not yet ' +
+ 'ready to migrate, react-create-class is available on npm as a ' +
+ 'drop-in replacement.'
+ );
+ console.error.calls.reset();
+ });
+
it('should throw when `render` is not specified', () => {
expect(function() {
React.createClass({});
diff --git a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js b/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js
deleted file mode 100644
index 3a3bb6288fa0b..0000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js
+++ /dev/null
@@ -1,545 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactTestUtils;
-
-var TestComponent;
-var TestComponentWithPropTypes;
-var TestComponentWithReverseSpec;
-var mixinPropValidator;
-var componentPropValidator;
-
-describe('ReactClass-mixin', () => {
-
- beforeEach(() => {
- React = require('React');
- ReactTestUtils = require('ReactTestUtils');
- mixinPropValidator = jest.fn();
- componentPropValidator = jest.fn();
-
- var MixinA = {
- propTypes: {
- propA: function() {},
- },
- componentDidMount: function() {
- this.props.listener('MixinA didMount');
- },
- };
-
- var MixinB = {
- mixins: [MixinA],
- propTypes: {
- propB: function() {},
- },
- componentDidMount: function() {
- this.props.listener('MixinB didMount');
- },
- };
-
- var MixinBWithReverseSpec = {
- componentDidMount: function() {
- this.props.listener('MixinBWithReverseSpec didMount');
- },
- mixins: [MixinA],
- };
-
- var MixinC = {
- statics: {
- staticC: function() {},
- },
- componentDidMount: function() {
- this.props.listener('MixinC didMount');
- },
- };
-
- var MixinD = {
- propTypes: {
- value: mixinPropValidator,
- },
- };
-
- TestComponent = React.createClass({
- mixins: [MixinB, MixinC, MixinD],
- statics: {
- staticComponent: function() {},
- },
- propTypes: {
- propComponent: function() {},
- },
- componentDidMount: function() {
- this.props.listener('Component didMount');
- },
- render: function() {
- return ;
- },
- });
-
- TestComponentWithReverseSpec = React.createClass({
- render: function() {
- return ;
- },
- componentDidMount: function() {
- this.props.listener('Component didMount');
- },
- mixins: [MixinBWithReverseSpec, MixinC, MixinD],
- });
-
- TestComponentWithPropTypes = React.createClass({
- mixins: [MixinD],
- propTypes: {
- value: componentPropValidator,
- },
- render: function() {
- return ;
- },
- });
- });
-
- it('should support merging propTypes and statics', () => {
- var listener = jest.fn();
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
-
- var instancePropTypes = instance.constructor.propTypes;
-
- expect('propA' in instancePropTypes).toBe(true);
- expect('propB' in instancePropTypes).toBe(true);
- expect('propComponent' in instancePropTypes).toBe(true);
-
- expect('staticC' in TestComponent).toBe(true);
- expect('staticComponent' in TestComponent).toBe(true);
- });
-
- it('should support chaining delegate functions', () => {
- var listener = jest.fn();
- var instance = ;
- ReactTestUtils.renderIntoDocument(instance);
-
- expect(listener.mock.calls).toEqual([
- ['MixinA didMount'],
- ['MixinB didMount'],
- ['MixinC didMount'],
- ['Component didMount'],
- ]);
- });
-
- it('should chain functions regardless of spec property order', () => {
- var listener = jest.fn();
- var instance = ;
- ReactTestUtils.renderIntoDocument(instance);
-
- expect(listener.mock.calls).toEqual([
- ['MixinA didMount'],
- ['MixinBWithReverseSpec didMount'],
- ['MixinC didMount'],
- ['Component didMount'],
- ]);
- });
-
- it('should validate prop types via mixins', () => {
- expect(TestComponent.propTypes).toBeDefined();
- expect(TestComponent.propTypes.value)
- .toBe(mixinPropValidator);
- });
-
- it('should override mixin prop types with class prop types', () => {
- // Sanity check...
- expect(componentPropValidator).not.toBe(mixinPropValidator);
- // Actually check...
- expect(TestComponentWithPropTypes.propTypes)
- .toBeDefined();
- expect(TestComponentWithPropTypes.propTypes.value)
- .not.toBe(mixinPropValidator);
- expect(TestComponentWithPropTypes.propTypes.value)
- .toBe(componentPropValidator);
- });
-
-
- it('should support mixins with getInitialState()', () => {
- var Mixin = {
- getInitialState: function() {
- return {mixin: true};
- },
- };
- var Component = React.createClass({
- mixins: [Mixin],
- getInitialState: function() {
- return {component: true};
- },
- render: function() {
- return ;
- },
- });
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state.component).toBe(true);
- expect(instance.state.mixin).toBe(true);
- });
-
- it('should throw with conflicting getInitialState() methods', () => {
- var Mixin = {
- getInitialState: function() {
- return {x: true};
- },
- };
- var Component = React.createClass({
- mixins: [Mixin],
- getInitialState: function() {
- return {x: true};
- },
- render: function() {
- return ;
- },
- });
- var instance = ;
- expect(function() {
- instance = ReactTestUtils.renderIntoDocument(instance);
- }).toThrowError(
- 'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the ' +
- 'same key: `x`. This conflict may be due to a mixin; in particular, ' +
- 'this may be caused by two getInitialState() or getDefaultProps() ' +
- 'methods returning objects with clashing keys.'
- );
- });
-
- it('should not mutate objects returned by getInitialState()', () => {
- var Mixin = {
- getInitialState: function() {
- return Object.freeze({mixin: true});
- },
- };
- var Component = React.createClass({
- mixins: [Mixin],
- getInitialState: function() {
- return Object.freeze({component: true});
- },
- render: function() {
- return ;
- },
- });
- expect(() => {
- ReactTestUtils.renderIntoDocument();
- }).not.toThrow();
- });
-
- it('should support statics in mixins', () => {
- var Mixin = {
- statics: {
- foo: 'bar',
- },
- };
- var Component = React.createClass({
- mixins: [Mixin],
-
- statics: {
- abc: 'def',
- },
-
- render: function() {
- return ;
- },
- });
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.constructor.foo).toBe('bar');
- expect(Component.foo).toBe('bar');
- expect(instance.constructor.abc).toBe('def');
- expect(Component.abc).toBe('def');
- });
-
- it("should throw if mixins override each others' statics", () => {
- expect(function() {
- var Mixin = {
- statics: {
- abc: 'foo',
- },
- };
- React.createClass({
- mixins: [Mixin],
-
- statics: {
- abc: 'bar',
- },
-
- render: function() {
- return ;
- },
- });
- }).toThrowError(
- 'ReactClass: You are attempting to define `abc` on your component more ' +
- 'than once. This conflict may be due to a mixin.'
- );
- });
-
- it('should throw if mixins override functions in statics', () => {
- expect(function() {
- var Mixin = {
- statics: {
- abc: function() {
- console.log('foo');
- },
- },
- };
- React.createClass({
- mixins: [Mixin],
-
- statics: {
- abc: function() {
- console.log('bar');
- },
- },
-
- render: function() {
- return ;
- },
- });
- }).toThrowError(
- 'ReactClass: You are attempting to define `abc` on your component ' +
- 'more than once. This conflict may be due to a mixin.'
- );
- });
-
- it('should warn if the mixin is undefined', () => {
- spyOn(console, 'error');
-
- React.createClass({
- mixins: [undefined],
-
- render: function() {
- return ;
- },
- });
-
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.argsFor(0)[0]).toBe(
- 'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
- 'either null or not an object. Check the mixins included by the ' +
- 'component, as well as any mixins they include themselves. ' +
- 'Expected object but got undefined.'
- );
- });
-
- it('should warn if the mixin is null', () => {
- spyOn(console, 'error');
-
- React.createClass({
- mixins: [null],
-
- render: function() {
- return ;
- },
- });
-
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.argsFor(0)[0]).toBe(
- 'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
- 'either null or not an object. Check the mixins included by the ' +
- 'component, as well as any mixins they include themselves. ' +
- 'Expected object but got null.'
- );
- });
-
- it('should warn if an undefined mixin is included in another mixin', () => {
- spyOn(console, 'error');
-
- var mixinA = {
- mixins: [undefined],
- };
-
- React.createClass({
- mixins: [mixinA],
-
- render: function() {
- return ;
- },
- });
-
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.argsFor(0)[0]).toBe(
- 'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
- 'either null or not an object. Check the mixins included by the ' +
- 'component, as well as any mixins they include themselves. ' +
- 'Expected object but got undefined.'
- );
- });
-
- it('should warn if a null mixin is included in another mixin', () => {
- spyOn(console, 'error');
-
- var mixinA = {
- mixins: [null],
- };
-
- React.createClass({
- mixins: [mixinA],
-
- render: function() {
- return ;
- },
- });
-
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.argsFor(0)[0]).toBe(
- 'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
- 'either null or not an object. Check the mixins included by the ' +
- 'component, as well as any mixins they include themselves. ' +
- 'Expected object but got null.'
- );
- });
-
- it('should throw if the mixin is a React component', () => {
- expect(function() {
- React.createClass({
- mixins: [],
-
- render: function() {
- return ;
- },
- });
- }).toThrowError(
- 'ReactClass: You\'re attempting to use a component as a mixin. ' +
- 'Instead, just use a regular object.'
- );
- });
-
- it('should throw if the mixin is a React component class', () => {
- expect(function() {
- var Component = React.createClass({
- render: function() {
- return ;
- },
- });
-
- React.createClass({
- mixins: [Component],
-
- render: function() {
- return ;
- },
- });
- }).toThrowError(
- 'ReactClass: You\'re attempting to use a component class or function ' +
- 'as a mixin. Instead, just use a regular object.'
- );
- });
-
- it('should have bound the mixin methods to the component', () => {
- var mixin = {
- mixinFunc: function() {
- return this;
- },
- };
-
- var Component = React.createClass({
- mixins: [mixin],
- componentDidMount: function() {
- expect(this.mixinFunc()).toBe(this);
- },
- render: function() {
- return ;
- },
- });
- var instance = ;
- ReactTestUtils.renderIntoDocument(instance);
- });
-
- it('should include the mixin keys in even if their values are falsy', () => {
- var mixin = {
- keyWithNullValue: null,
- randomCounter: 0,
- };
-
- var Component = React.createClass({
- mixins: [mixin],
- componentDidMount: function() {
- expect(this.randomCounter).toBe(0);
- expect(this.keyWithNullValue).toBeNull();
- },
- render: function() {
- return ;
- },
- });
- var instance = ;
- ReactTestUtils.renderIntoDocument(instance);
- });
-
- it('should work with a null getInitialState return value and a mixin', () => {
- var Component;
- var instance;
-
- var Mixin = {
- getInitialState: function() {
- return {foo: 'bar'};
- },
- };
- Component = React.createClass({
- mixins: [Mixin],
- getInitialState: function() {
- return null;
- },
- render: function() {
- return ;
- },
- });
- expect(
- () => ReactTestUtils.renderIntoDocument()
- ).not.toThrow();
-
- instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'bar'});
-
- // Also the other way round should work
- var Mixin2 = {
- getInitialState: function() {
- return null;
- },
- };
- Component = React.createClass({
- mixins: [Mixin2],
- getInitialState: function() {
- return {foo: 'bar'};
- },
- render: function() {
- return ;
- },
- });
- expect(
- () => ReactTestUtils.renderIntoDocument()
- ).not.toThrow();
-
- instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'bar'});
-
- // Multiple mixins should be fine too
- Component = React.createClass({
- mixins: [Mixin, Mixin2],
- getInitialState: function() {
- return {x: true};
- },
- render: function() {
- return ;
- },
- });
- expect(
- () => ReactTestUtils.renderIntoDocument()
- ).not.toThrow();
-
- instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'bar', x: true});
- });
-
-});
diff --git a/src/isomorphic/classic/element/__tests__/ReactElement-test.js b/src/isomorphic/classic/element/__tests__/ReactElement-test.js
index 36814982c3f1d..cf82a953094ac 100644
--- a/src/isomorphic/classic/element/__tests__/ReactElement-test.js
+++ b/src/isomorphic/classic/element/__tests__/ReactElement-test.js
@@ -32,11 +32,11 @@ describe('ReactElement', () => {
ReactTestUtils = require('ReactTestUtils');
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
- ComponentClass = React.createClass({
- render: function() {
+ ComponentClass = class extends React.Component {
+ render() {
return React.createElement('div');
- },
- });
+ }
+ };
});
afterEach(() => {
@@ -57,37 +57,7 @@ describe('ReactElement', () => {
expect(element.props).toEqual({});
});
- it('should warn when `key` is being accessed on createClass element', () => {
- spyOn(console, 'error');
- var container = document.createElement('div');
- var Child = React.createClass({
- render: function() {
- return {this.props.key}
;
- },
- });
- var Parent = React.createClass({
- render: function() {
- return (
-
-
-
-
-
- );
- },
- });
- expect(console.error.calls.count()).toBe(0);
- ReactDOM.render(, container);
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.argsFor(0)[0]).toContain(
- 'Child: `key` is not a prop. Trying to access it will result ' +
- 'in `undefined` being returned. If you need to access the same ' +
- 'value within the child component, you should pass it as a different ' +
- 'prop. (https://fb.me/react-special-props)'
- );
- });
-
- it('should warn when `key` is being accessed on ES class element', () => {
+ it('should warn when `key` is being accessed on composite element', () => {
spyOn(console, 'error');
var container = document.createElement('div');
class Child extends React.Component {
@@ -95,8 +65,8 @@ describe('ReactElement', () => {
return {this.props.key}
;
}
}
- var Parent = React.createClass({
- render: function() {
+ class Parent extends React.Component {
+ render() {
return (
@@ -104,8 +74,8 @@ describe('ReactElement', () => {
);
- },
- });
+ }
+ }
expect(console.error.calls.count()).toBe(0);
ReactDOM.render(, container);
expect(console.error.calls.count()).toBe(1);
@@ -134,20 +104,20 @@ describe('ReactElement', () => {
it('should warn when `ref` is being accessed', () => {
spyOn(console, 'error');
var container = document.createElement('div');
- var Child = React.createClass({
- render: function() {
+ class Child extends React.Component {
+ render() {
return {this.props.ref}
;
- },
- });
- var Parent = React.createClass({
- render: function() {
+ }
+ }
+ class Parent extends React.Component {
+ render() {
return (
);
- },
- });
+ }
+ }
expect(console.error.calls.count()).toBe(0);
ReactDOM.render(, container);
expect(console.error.calls.count()).toBe(1);
@@ -255,12 +225,12 @@ describe('ReactElement', () => {
var Component = React.createFactory(ComponentClass);
var element;
- var Wrapper = React.createClass({
- render: function() {
+ class Wrapper extends React.Component {
+ render() {
element = Component();
return element;
- },
- });
+ }
+ }
var instance = ReactTestUtils.renderIntoDocument(
React.createElement(Wrapper)
@@ -312,19 +282,12 @@ describe('ReactElement', () => {
it('allows static methods to be called using the type property', () => {
spyOn(console, 'error');
- var StaticMethodComponentClass = React.createClass({
- statics: {
- someStaticMethod: function() {
- return 'someReturnValue';
- },
- },
- getInitialState: function() {
- return {valueToReturn: 'hi'};
- },
- render: function() {
+ class StaticMethodComponentClass extends React.Component {
+ render() {
return React.createElement('div');
- },
- });
+ }
+ }
+ StaticMethodComponentClass.someStaticMethod = () => 'someReturnValue';
var element = React.createElement(StaticMethodComponentClass);
expect(element.type.someStaticMethod()).toBe('someReturnValue');
@@ -334,11 +297,11 @@ describe('ReactElement', () => {
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('identifies valid elements', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('div');
- },
- });
+ }
+ }
expect(React.isValidElement(React.createElement('div')))
.toEqual(true);
@@ -357,21 +320,6 @@ describe('ReactElement', () => {
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
});
- it('allows the use of PropTypes validators in statics', () => {
- // TODO: This test was added to cover a special case where we proxied
- // methods. However, we don't do that any more so this test can probably
- // be removed. Leaving it in classic as a safety precaution.
- var Component = React.createClass({
- render: () => null,
- statics: {
- specialType: React.PropTypes.shape({monkey: React.PropTypes.any}),
- },
- });
-
- expect(typeof Component.specialType).toBe('function');
- expect(typeof Component.specialType.isRequired).toBe('function');
- });
-
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('is indistinguishable from a plain object', () => {
@@ -383,14 +331,12 @@ describe('ReactElement', () => {
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('should use default prop value when removing a prop', () => {
- var Component = React.createClass({
- getDefaultProps: function() {
- return {fruit: 'persimmon'};
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('span');
- },
- });
+ }
+ }
+ Component.defaultProps = {fruit: 'persimmon'};
var container = document.createElement('div');
var instance = ReactDOM.render(
@@ -406,14 +352,12 @@ describe('ReactElement', () => {
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('should normalize props with default values', () => {
- var Component = React.createClass({
- getDefaultProps: function() {
- return {prop: 'testKey'};
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('span', null, this.props.prop);
- },
- });
+ }
+ }
+ Component.defaultProps = {prop: 'testKey'};
var instance = ReactTestUtils.renderIntoDocument(
React.createElement(Component)
@@ -427,8 +371,8 @@ describe('ReactElement', () => {
});
it('throws when changing a prop (in dev) after element creation', () => {
- var Outer = React.createClass({
- render: function() {
+ class Outer extends React.Component {
+ render() {
var el = ;
expect(function() {
@@ -437,17 +381,16 @@ describe('ReactElement', () => {
expect(el.props.className).toBe('moo');
return el;
- },
- });
+ }
+ }
var outer = ReactTestUtils.renderIntoDocument();
expect(ReactDOM.findDOMNode(outer).className).toBe('moo');
});
it('throws when adding a prop (in dev) after element creation', () => {
var container = document.createElement('div');
- var Outer = React.createClass({
- getDefaultProps: () => ({sound: 'meow'}),
- render: function() {
+ class Outer extends React.Component {
+ render() {
var el = {this.props.sound}
;
expect(function() {
@@ -457,8 +400,9 @@ describe('ReactElement', () => {
expect(el.props.className).toBe(undefined);
return el;
- },
- });
+ }
+ }
+ Outer.defaultProps = {sound: 'meow'};
var outer = ReactDOM.render(, container);
expect(ReactDOM.findDOMNode(outer).textContent).toBe('meow');
expect(ReactDOM.findDOMNode(outer).className).toBe('');
@@ -466,11 +410,11 @@ describe('ReactElement', () => {
it('does not warn for NaN props', () => {
spyOn(console, 'error');
- var Test = React.createClass({
- render: function() {
+ class Test extends React.Component {
+ render() {
return ;
- },
- });
+ }
+ }
var test = ReactTestUtils.renderIntoDocument();
expect(test.props.value).toBeNaN();
expect(console.error.calls.count()).toBe(0);
@@ -498,11 +442,11 @@ describe('ReactElement', () => {
React = require('React');
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('div');
- },
- });
+ }
+ }
expect(React.isValidElement(React.createElement('div')))
.toEqual(true);
@@ -538,15 +482,15 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
describe('when using jsx only', () => {
var Parent, instance;
beforeEach(() => {
- Parent = React.createClass({
- render: function() {
+ Parent = class extends React.Component {
+ render() {
return (
children value
);
- },
- });
+ }
+ };
instance = ReactTestUtils.renderIntoDocument();
});
@@ -568,11 +512,11 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
var factory, instance;
beforeEach(() => {
var childFactory = React.createFactory(Child);
- var Parent = React.createClass({
- render: function() {
+ class Parent extends React.Component {
+ render() {
return React.DOM.div({}, childFactory({ ref: 'child', foo: 'foo value' }, 'children value'));
- },
- });
+ }
+ }
factory = React.createFactory(Parent);
instance = ReactTestUtils.renderIntoDocument(factory());
});
@@ -594,11 +538,11 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
describe('when using parent that uses .createElement()', () => {
var factory, instance;
beforeEach(() => {
- var Parent = React.createClass({
- render: function() {
+ class Parent extends React.Component {
+ render() {
return React.DOM.div({}, React.createElement(Child, { ref: 'child', foo: 'foo value' }, 'children value'));
- },
- });
+ }
+ }
factory = React.createFactory(Parent);
instance = ReactTestUtils.renderIntoDocument(factory());
});
diff --git a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js
index 50406d03456d6..69e8984ca2f8b 100644
--- a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js
+++ b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js
@@ -25,52 +25,52 @@ describe('ReactElementClone', () => {
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
- ComponentClass = React.createClass({
- render: function() {
+ ComponentClass = class extends React.Component {
+ render() {
return React.createElement('div');
- },
- });
+ }
+ };
});
it('should clone a DOM component with new props', () => {
- var Grandparent = React.createClass({
- render: function() {
+ class Grandparent extends React.Component {
+ render() {
return } />;
- },
- });
- var Parent = React.createClass({
- render: function() {
+ }
+ }
+ class Parent extends React.Component {
+ render() {
return (
{React.cloneElement(this.props.child, { className: 'xyz' })}
);
- },
- });
+ }
+ }
var component = ReactTestUtils.renderIntoDocument();
expect(ReactDOM.findDOMNode(component).childNodes[0].className).toBe('xyz');
});
it('should clone a composite component with new props', () => {
- var Child = React.createClass({
- render: function() {
+ class Child extends React.Component {
+ render() {
return ;
- },
- });
- var Grandparent = React.createClass({
- render: function() {
+ }
+ }
+ class Grandparent extends React.Component {
+ render() {
return } />;
- },
- });
- var Parent = React.createClass({
- render: function() {
+ }
+ }
+ class Parent extends React.Component {
+ render() {
return (
{React.cloneElement(this.props.child, { className: 'xyz' })}
);
- },
- });
+ }
+ }
var component = ReactTestUtils.renderIntoDocument();
expect(ReactDOM.findDOMNode(component).childNodes[0].className).toBe('xyz');
});
@@ -81,43 +81,43 @@ describe('ReactElementClone', () => {
});
it('should keep the original ref if it is not overridden', () => {
- var Grandparent = React.createClass({
- render: function() {
+ class Grandparent extends React.Component {
+ render() {
return } />;
- },
- });
+ }
+ }
- var Parent = React.createClass({
- render: function() {
+ class Parent extends React.Component {
+ render() {
return (
{React.cloneElement(this.props.child, { className: 'xyz' })}
);
- },
- });
+ }
+ }
var component = ReactTestUtils.renderIntoDocument();
expect(component.refs.yolo.tagName).toBe('DIV');
});
it('should transfer the key property', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
return null;
- },
- });
+ }
+ }
var clone = React.cloneElement(, {key: 'xyz'});
expect(clone.key).toBe('xyz');
});
it('should transfer children', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
expect(this.props.children).toBe('xyz');
return ;
- },
- });
+ }
+ }
ReactTestUtils.renderIntoDocument(
React.cloneElement(, {children: 'xyz'})
@@ -125,12 +125,12 @@ describe('ReactElementClone', () => {
});
it('should shallow clone children', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
expect(this.props.children).toBe('xyz');
return ;
- },
- });
+ }
+ }
ReactTestUtils.renderIntoDocument(
React.cloneElement(xyz, {})
@@ -138,11 +138,11 @@ describe('ReactElementClone', () => {
});
it('should accept children as rest arguments', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
return null;
- },
- });
+ }
+ }
var clone = React.cloneElement(
xyz,
@@ -170,39 +170,39 @@ describe('ReactElementClone', () => {
});
it('should support keys and refs', () => {
- var Parent = React.createClass({
- render: function() {
+ class Parent extends React.Component {
+ render() {
var clone =
React.cloneElement(this.props.children, {key: 'xyz', ref: 'xyz'});
expect(clone.key).toBe('xyz');
expect(clone.ref).toBe('xyz');
return {clone}
;
- },
- });
+ }
+ }
- var Grandparent = React.createClass({
- render: function() {
+ class Grandparent extends React.Component {
+ render() {
return ;
- },
- });
+ }
+ }
var component = ReactTestUtils.renderIntoDocument();
expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
});
it('should steal the ref if a new ref is specified', () => {
- var Parent = React.createClass({
- render: function() {
+ class Parent extends React.Component {
+ render() {
var clone = React.cloneElement(this.props.children, {ref: 'xyz'});
return {clone}
;
- },
- });
+ }
+ }
- var Grandparent = React.createClass({
- render: function() {
+ class Grandparent extends React.Component {
+ render() {
return ;
- },
- });
+ }
+ }
var component = ReactTestUtils.renderIntoDocument();
expect(component.refs.child).toBeUndefined();
@@ -210,12 +210,12 @@ describe('ReactElementClone', () => {
});
it('should overwrite props', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
expect(this.props.myprop).toBe('xyz');
return ;
- },
- });
+ }
+ }
ReactTestUtils.renderIntoDocument(
React.cloneElement(, {myprop: 'xyz'})
@@ -223,14 +223,12 @@ describe('ReactElementClone', () => {
});
it('should normalize props with default values', () => {
- var Component = React.createClass({
- getDefaultProps: function() {
- return {prop: 'testKey'};
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return ;
- },
- });
+ }
+ }
+ Component.defaultProps = {prop: 'testKey'};
var instance = React.createElement(Component);
var clonedInstance = React.cloneElement(instance, {prop: undefined});
@@ -282,27 +280,27 @@ describe('ReactElementClone', () => {
it('should check declared prop types after clone', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- propTypes: {
- color: React.PropTypes.string.isRequired,
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('div', null, 'My color is ' + this.color);
- },
- });
- var Parent = React.createClass({
- render: function() {
+ }
+ }
+ Component.propTypes = {
+ color: React.PropTypes.string.isRequired,
+ };
+ class Parent extends React.Component {
+ render() {
return React.cloneElement(this.props.child, {color: 123});
- },
- });
- var GrandParent = React.createClass({
- render: function() {
+ }
+ }
+ class GrandParent extends React.Component {
+ render() {
return React.createElement(
Parent,
{ child: React.createElement(Component, {color: 'red'}) }
);
- },
- });
+ }
+ }
ReactTestUtils.renderIntoDocument(React.createElement(GrandParent));
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toBe(
diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
index b36fa2f39c9ab..17367f0439c90 100644
--- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
+++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
@@ -31,11 +31,11 @@ describe('ReactElementValidator', () => {
React = require('React');
ReactDOM = require('ReactDOM');
ReactTestUtils = require('ReactTestUtils');
- ComponentClass = React.createClass({
- render: function() {
+ ComponentClass = class extends React.Component {
+ render() {
return React.createElement('div');
- },
- });
+ }
+ };
});
it('warns for keys for arrays of elements in rest args', () => {
@@ -54,21 +54,19 @@ describe('ReactElementValidator', () => {
spyOn(console, 'error');
var Component = React.createFactory(ComponentClass);
- var InnerClass = React.createClass({
- displayName: 'InnerClass',
- render: function() {
+ class InnerClass extends React.Component {
+ render() {
return Component(null, this.props.childSet);
- },
- });
+ }
+ }
var InnerComponent = React.createFactory(InnerClass);
- var ComponentWrapper = React.createClass({
- displayName: 'ComponentWrapper',
- render: function() {
+ class ComponentWrapper extends React.Component {
+ render() {
return InnerComponent({childSet: [Component(), Component()] });
- },
- });
+ }
+ }
ReactTestUtils.renderIntoDocument(
React.createElement(ComponentWrapper)
@@ -85,12 +83,10 @@ describe('ReactElementValidator', () => {
it('warns for keys for arrays with no owner or parent info', () => {
spyOn(console, 'error');
- var Anonymous = React.createClass({
- displayName: undefined,
- render: function() {
- return ;
- },
- });
+ function Anonymous() {
+ return ;
+ }
+ Object.defineProperty(Anonymous, 'name', { value: undefined });
var divs = [
,
@@ -127,23 +123,17 @@ describe('ReactElementValidator', () => {
it('warns for keys with component stack info', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- render: function() {
- return ;
- },
- });
+ function Component() {
+ return ;
+ }
- var Parent = React.createClass({
- render: function() {
- return React.cloneElement(this.props.child);
- },
- });
+ function Parent(props) {
+ return React.cloneElement(props.child);
+ }
- var GrandParent = React.createClass({
- render: function() {
- return } />;
- },
- });
+ function GrandParent() {
+ return } />;
+ }
ReactTestUtils.renderIntoDocument();
@@ -162,16 +152,14 @@ describe('ReactElementValidator', () => {
it('does not warn for keys when passing children down', () => {
spyOn(console, 'error');
- var Wrapper = React.createClass({
- render: function() {
- return (
-
- {this.props.children}
-
-
- );
- },
- });
+ function Wrapper(props) {
+ return (
+
+ {props.children}
+
+
+ );
+ }
ReactTestUtils.renderIntoDocument(
@@ -266,19 +254,15 @@ describe('ReactElementValidator', () => {
// component, we give a small hint as to which parent instantiated that
// component as per warnings about key usage in ReactElementValidator.
spyOn(console, 'error');
- var MyComp = React.createClass({
- propTypes: {
- color: React.PropTypes.string,
- },
- render: function() {
- return React.createElement('div', null, 'My color is ' + this.color);
- },
- });
- var ParentComp = React.createClass({
- render: function() {
- return React.createElement(MyComp, {color: 123});
- },
- });
+ function MyComp(props) {
+ return React.createElement('div', null, 'My color is ' + props.color);
+ }
+ MyComp.propTypes = {
+ color: React.PropTypes.string,
+ };
+ function ParentComp() {
+ return React.createElement(MyComp, {color: 123});
+ }
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
expect(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Failed prop type: ' +
@@ -336,11 +320,9 @@ describe('ReactElementValidator', () => {
it('includes the owner name when passing null, undefined, boolean, or number', () => {
spyOn(console, 'error');
- var ParentComp = React.createClass({
- render: function() {
- return React.createElement(null);
- },
- });
+ function ParentComp() {
+ return React.createElement(null);
+ }
expect(function() {
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
}).toThrowError(
@@ -359,15 +341,13 @@ describe('ReactElementValidator', () => {
it('should check default prop values', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- propTypes: {prop: React.PropTypes.string.isRequired},
- getDefaultProps: function() {
- return {prop: null};
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('span', null, this.props.prop);
- },
- });
+ }
+ }
+ Component.propTypes = {prop: React.PropTypes.string.isRequired};
+ Component.defaultProps = {prop: null};
ReactTestUtils.renderIntoDocument(React.createElement(Component));
@@ -382,15 +362,13 @@ describe('ReactElementValidator', () => {
it('should not check the default for explicit null', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- propTypes: {prop: React.PropTypes.string.isRequired},
- getDefaultProps: function() {
- return {prop: 'text'};
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('span', null, this.props.prop);
- },
- });
+ }
+ }
+ Component.propTypes = {prop: React.PropTypes.string.isRequired};
+ Component.defaultProps = {prop: 'text'};
ReactTestUtils.renderIntoDocument(
React.createElement(Component, {prop:null})
@@ -407,14 +385,14 @@ describe('ReactElementValidator', () => {
it('should check declared prop types', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- propTypes: {
- prop: React.PropTypes.string.isRequired,
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('span', null, this.props.prop);
- },
- });
+ }
+ }
+ Component.propTypes = {
+ prop: React.PropTypes.string.isRequired,
+ };
ReactTestUtils.renderIntoDocument(
React.createElement(Component)
@@ -449,14 +427,15 @@ describe('ReactElementValidator', () => {
it('should warn if a PropType creator is used as a PropType', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- propTypes: {
- myProp: React.PropTypes.shape,
- },
- render: function() {
+ class Component extends React.Component {
+ render() {
return React.createElement('span', null, this.props.myProp.value);
- },
- });
+
+ }
+ }
+ Component.propTypes = {
+ myProp: React.PropTypes.shape,
+ };
ReactTestUtils.renderIntoDocument(
React.createElement(Component, {myProp: {value: 'hi'}})
@@ -474,11 +453,9 @@ describe('ReactElementValidator', () => {
it('should warn when accessing .type on an element factory', () => {
spyOn(console, 'error');
- var TestComponent = React.createClass({
- render: function() {
- return ;
- },
- });
+ function TestComponent() {
+ return ;
+ }
var TestFactory = React.createFactory(TestComponent);
expect(TestFactory.type).toBe(TestComponent);
expect(console.error.calls.count()).toBe(1);
@@ -493,14 +470,14 @@ describe('ReactElementValidator', () => {
it('does not warn when using DOM node as children', () => {
spyOn(console, 'error');
- var DOMContainer = React.createClass({
- render: function() {
+ class DOMContainer extends React.Component {
+ render() {
return ;
- },
- componentDidMount: function() {
+ }
+ componentDidMount() {
ReactDOM.findDOMNode(this).appendChild(this.props.children);
- },
- });
+ }
+ }
var node = document.createElement('div');
// This shouldn't cause a stack overflow or any other problems (#3883)
diff --git a/src/renderers/dom/client/__tests__/ReactMount-test.js b/src/renderers/dom/client/__tests__/ReactMount-test.js
index 7e574216bdc7e..d9d9e5eff14a5 100644
--- a/src/renderers/dom/client/__tests__/ReactMount-test.js
+++ b/src/renderers/dom/client/__tests__/ReactMount-test.js
@@ -91,13 +91,13 @@ describe('ReactMount', () => {
var mockMount = jest.fn();
var mockUnmount = jest.fn();
- var Component = React.createClass({
- componentDidMount: mockMount,
- componentWillUnmount: mockUnmount,
- render: function() {
+ class Component extends React.Component {
+ componentDidMount = mockMount;
+ componentWillUnmount = mockUnmount;
+ render() {
return {this.props.text};
- },
- });
+ }
+ }
expect(mockMount.mock.calls.length).toBe(0);
expect(mockUnmount.mock.calls.length).toBe(0);
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js
index d39527f5c0a04..5d2ec7ab88bc9 100644
--- a/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js
+++ b/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js
@@ -184,9 +184,11 @@ describe('BeforeInputEventPlugin', function() {
function TestEditableReactComponent(Emulator, Scenario, ExpectedResult) {
ModuleCache = new initialize(Emulator);
- var EditableDiv = React.createClass({
- render: () => (),
- });
+ class EditableDiv extends React.Component {
+ render() {
+ return ;
+ }
+ }
var rendered = ReactTestUtils.renderIntoDocument();
var node = ModuleCache.ReactDOM.findDOMNode(rendered);
diff --git a/src/renderers/dom/server/__tests__/ReactServerRendering-test.js b/src/renderers/dom/server/__tests__/ReactServerRendering-test.js
index 26db5640693b2..af931eb408d30 100644
--- a/src/renderers/dom/server/__tests__/ReactServerRendering-test.js
+++ b/src/renderers/dom/server/__tests__/ReactServerRendering-test.js
@@ -486,32 +486,6 @@ describe('ReactServerRendering', () => {
expect(markup).toBe('hello
');
});
- it('warns with a no-op when an async replaceState is triggered', () => {
- var Bar = React.createClass({
- componentWillMount: function() {
- this.replaceState({text: 'hello'});
- setTimeout(() => {
- this.replaceState({text: 'error'});
- });
- },
- render: function() {
- return {}}>{this.state.text}
;
- },
- });
-
- spyOn(console, 'error');
- ReactServerRendering.renderToString();
- jest.runOnlyPendingTimers();
- expect(console.error.calls.count()).toBe(1);
- expect(console.error.calls.mostRecent().args[0]).toBe(
- 'Warning: replaceState(...): Can only update a mounting component. ' +
- 'This usually means you called replaceState() outside componentWillMount() on the server. ' +
- 'This is a no-op. Please check the code for the Bar component.'
- );
- var markup = ReactServerRendering.renderToStaticMarkup();
- expect(markup).toBe('hello
');
- });
-
it('warns with a no-op when an async forceUpdate is triggered', () => {
class Baz extends React.Component {
componentWillMount() {
diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
index 34e14145a79c7..71bb4cb1824be 100644
--- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
@@ -187,18 +187,14 @@ describe('ReactDOMComponent', () => {
spyOn(console, 'error');
var div = document.createElement('div');
- var One = React.createClass({
- render: function() {
- return this.props.inline ?
- :
- ;
- },
- });
- var Two = React.createClass({
- render: function() {
- return ;
- },
- });
+ function One(props) {
+ return props.inline ?
+ :
+ ;
+ }
+ function Two() {
+ return ;
+ }
ReactDOM.render(, div);
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toBe(
@@ -1256,12 +1252,12 @@ describe('ReactDOMComponent', () => {
it('gives useful context in warnings', () => {
spyOn(console, 'error');
- var Row = React.createClass({
- render: () =>
,
- });
- var FancyRow = React.createClass({
- render: () =>
,
- });
+ function Row() {
+ return
;
+ }
+ function FancyRow() {
+ return
;
+ }
class Table extends React.Component {
render() {
@@ -1275,24 +1271,24 @@ describe('ReactDOMComponent', () => {
}
}
- var Viz1 = React.createClass({
- render: () => ,
- });
- var App1 = React.createClass({
- render: () => ,
- });
+ function Viz1() {
+ return ;
+ }
+ function App1() {
+ return ;
+ }
ReactTestUtils.renderIntoDocument();
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'See Viz1 > table > FancyRow > Row > tr.'
);
- var Viz2 = React.createClass({
- render: () => ,
- });
- var App2 = React.createClass({
- render: () => ,
- });
+ function Viz2() {
+ return ;
+ }
+ function App2() {
+ return ;
+ }
ReactTestUtils.renderIntoDocument();
expect(console.error.calls.count()).toBe(2);
expect(console.error.calls.argsFor(1)[0]).toContain(
diff --git a/src/renderers/shared/__tests__/ReactPerf-test.js b/src/renderers/shared/__tests__/ReactPerf-test.js
index dfd1e517fc2dc..25ffd77d7bc76 100644
--- a/src/renderers/shared/__tests__/ReactPerf-test.js
+++ b/src/renderers/shared/__tests__/ReactPerf-test.js
@@ -59,16 +59,16 @@ describe('ReactPerf', () => {
}
};
- LifeCycle = React.createClass({
- shouldComponentUpdate: emptyFunction.thatReturnsTrue,
- componentWillMount: emptyFunction,
- componentDidMount: emptyFunction,
- componentWillReceiveProps: emptyFunction,
- componentWillUpdate: emptyFunction,
- componentDidUpdate: emptyFunction,
- componentWillUnmount: emptyFunction,
- render: emptyFunction.thatReturnsNull,
- });
+ LifeCycle = class extends React.Component {
+ shouldComponentUpdate = emptyFunction.thatReturnsTrue;
+ componentWillMount = emptyFunction;
+ componentDidMount = emptyFunction;
+ componentWillReceiveProps = emptyFunction;
+ componentWillUpdate = emptyFunction;
+ componentDidUpdate = emptyFunction;
+ componentWillUnmount = emptyFunction;
+ render = emptyFunction.thatReturnsNull;
+ };
});
afterEach(() => {
diff --git a/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
index f13573c91fdf9..24f0bddfa72ce 100644
--- a/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
+++ b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
@@ -751,15 +751,13 @@ describe('ReactIncremental', () => {
it('can replaceState', () => {
let instance;
- const Bar = React.createClass({
- getInitialState() {
- instance = this;
- return { a: 'a' };
- },
+ class Bar extends React.Component {
+ state = {a: 'a'};
render() {
+ instance = this;
return {this.props.children}
;
- },
- });
+ }
+ }
function Foo() {
return (
@@ -773,7 +771,7 @@ describe('ReactIncremental', () => {
ReactNoop.flush();
instance.setState({ b: 'b' });
instance.setState({ c: 'c' });
- instance.replaceState({ d: 'd' });
+ instance.updater.enqueueReplaceState(instance, {d: 'd'});
ReactNoop.flush();
expect(instance.state).toEqual({ d: 'd' });
});
diff --git a/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js b/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js
index 61fd34902d2e1..d639848ae2d6b 100644
--- a/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js
+++ b/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js
@@ -1743,8 +1743,15 @@ describe('ReactComponentTreeHook', () => {
return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
}
- var Anon = React.createClass({displayName: null, render: () => null});
- var Orange = React.createClass({render: () => null});
+ function Anon() {
+ return null;
+ }
+ Object.defineProperty(Anon, 'name', {
+ value: null,
+ });
+ function Orange() {
+ return null;
+ }
expect(getAddendum()).toBe(
''
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js
index a8a139b015b61..c1addcafd7030 100644
--- a/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js
@@ -245,23 +245,28 @@ describe('ReactComponentLifeCycle', () => {
it('should correctly determine if a component is mounted', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- componentWillMount: function() {
- expect(this.isMounted()).toBeFalsy();
- },
- componentDidMount: function() {
- expect(this.isMounted()).toBeTruthy();
- },
- render: function() {
- expect(this.isMounted()).toBeFalsy();
+ class Component extends React.Component {
+ _isMounted() {
+ // No longer a public API, but we can test that it works internally by
+ // reaching into the updater.
+ return this.updater.isMounted(this);
+ }
+ componentWillMount() {
+ expect(this._isMounted()).toBeFalsy();
+ }
+ componentDidMount() {
+ expect(this._isMounted()).toBeTruthy();
+ }
+ render() {
+ expect(this._isMounted()).toBeFalsy();
return ;
- },
- });
+ }
+ }
var element = ;
var instance = ReactTestUtils.renderIntoDocument(element);
- expect(instance.isMounted()).toBeTruthy();
+ expect(instance._isMounted()).toBeTruthy();
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
@@ -271,23 +276,28 @@ describe('ReactComponentLifeCycle', () => {
it('should correctly determine if a null component is mounted', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- componentWillMount: function() {
- expect(this.isMounted()).toBeFalsy();
- },
- componentDidMount: function() {
- expect(this.isMounted()).toBeTruthy();
- },
- render: function() {
- expect(this.isMounted()).toBeFalsy();
+ class Component extends React.Component {
+ _isMounted() {
+ // No longer a public API, but we can test that it works internally by
+ // reaching into the updater.
+ return this.updater.isMounted(this);
+ }
+ componentWillMount() {
+ expect(this._isMounted()).toBeFalsy();
+ }
+ componentDidMount() {
+ expect(this._isMounted()).toBeTruthy();
+ }
+ render() {
+ expect(this._isMounted()).toBeFalsy();
return null;
- },
- });
+ }
+ }
var element = ;
var instance = ReactTestUtils.renderIntoDocument(element);
- expect(instance.isMounted()).toBeTruthy();
+ expect(instance._isMounted()).toBeTruthy();
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
@@ -296,38 +306,38 @@ describe('ReactComponentLifeCycle', () => {
});
it('isMounted should return false when unmounted', () => {
- var Component = React.createClass({
- render: function() {
+ class Component extends React.Component {
+ render() {
return ;
- },
- });
+ }
+ }
var container = document.createElement('div');
var instance = ReactDOM.render(, container);
- expect(instance.isMounted()).toBe(true);
+ // No longer a public API, but we can test that it works internally by
+ // reaching into the updater.
+ expect(instance.updater.isMounted(instance)).toBe(true);
ReactDOM.unmountComponentAtNode(container);
- expect(instance.isMounted()).toBe(false);
+ expect(instance.updater.isMounted(instance)).toBe(false);
});
it('warns if findDOMNode is used inside render', () => {
spyOn(console, 'error');
- var Component = React.createClass({
- getInitialState: function() {
- return {isMounted: false};
- },
- componentDidMount: function() {
+ class Component extends React.Component {
+ state = {isMounted: false};
+ componentDidMount() {
this.setState({isMounted: true});
- },
- render: function() {
+ }
+ render() {
if (this.state.isMounted) {
expect(ReactDOM.findDOMNode(this).tagName).toBe('DIV');
}
return ;
- },
- });
+ }
+ }
ReactTestUtils.renderIntoDocument();
expect(console.error.calls.count()).toBe(1);
@@ -539,30 +549,31 @@ describe('ReactComponentLifeCycle', () => {
return true;
};
};
- var Outer = React.createClass({
- render: function() {
+ class Outer extends React.Component {
+ componentWillMount = logger('outer componentWillMount');
+ componentDidMount = logger('outer componentDidMount');
+ componentWillReceiveProps = logger('outer componentWillReceiveProps');
+ shouldComponentUpdate = logger('outer shouldComponentUpdate');
+ componentWillUpdate = logger('outer componentWillUpdate');
+ componentDidUpdate = logger('outer componentDidUpdate');
+ componentWillUnmount = logger('outer componentWillUnmount');
+ render() {
return
;
- },
- componentWillMount: logger('outer componentWillMount'),
- componentDidMount: logger('outer componentDidMount'),
- componentWillReceiveProps: logger('outer componentWillReceiveProps'),
- shouldComponentUpdate: logger('outer shouldComponentUpdate'),
- componentWillUpdate: logger('outer componentWillUpdate'),
- componentDidUpdate: logger('outer componentDidUpdate'),
- componentWillUnmount: logger('outer componentWillUnmount'),
- });
- var Inner = React.createClass({
- render: function() {
+ }
+ }
+
+ class Inner extends React.Component {
+ componentWillMount = logger('inner componentWillMount');
+ componentDidMount = logger('inner componentDidMount');
+ componentWillReceiveProps = logger('inner componentWillReceiveProps');
+ shouldComponentUpdate = logger('inner shouldComponentUpdate');
+ componentWillUpdate = logger('inner componentWillUpdate');
+ componentDidUpdate = logger('inner componentDidUpdate');
+ componentWillUnmount = logger('inner componentWillUnmount');
+ render() {
return {this.props.x};
- },
- componentWillMount: logger('inner componentWillMount'),
- componentDidMount: logger('inner componentDidMount'),
- componentWillReceiveProps: logger('inner componentWillReceiveProps'),
- shouldComponentUpdate: logger('inner shouldComponentUpdate'),
- componentWillUpdate: logger('inner componentWillUpdate'),
- componentDidUpdate: logger('inner componentDidUpdate'),
- componentWillUnmount: logger('inner componentWillUnmount'),
- });
+ }
+ }
var container = document.createElement('div');
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
index f38711594015f..66323dc6ed8bf 100644
--- a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
@@ -169,65 +169,6 @@ describe('ReactCompositeComponent', () => {
expect(instance.getAnchor().className).toBe('');
});
- it('should auto bind methods and values correctly', () => {
- spyOn(console, 'error');
-
- var ComponentClass = React.createClass({
- getInitialState: function() {
- return {valueToReturn: 'hi'};
- },
- methodToBeExplicitlyBound: function() {
- return this;
- },
- methodAutoBound: function() {
- return this;
- },
- render: function() {
- return ;
- },
- });
- var instance = ;
-
- // Next, prove that once mounted, the scope is bound correctly to the actual
- // component.
- var mountedInstance = ReactTestUtils.renderIntoDocument(instance);
-
- expect(function() {
- mountedInstance.methodToBeExplicitlyBound.bind(instance)();
- }).not.toThrow();
- expect(function() {
- mountedInstance.methodAutoBound();
- }).not.toThrow();
-
- expect(console.error.calls.count()).toBe(1);
- var explicitlyBound = mountedInstance.methodToBeExplicitlyBound.bind(
- mountedInstance
- );
- expect(console.error.calls.count()).toBe(2);
- var autoBound = mountedInstance.methodAutoBound;
-
- var context = {};
- expect(explicitlyBound.call(context)).toBe(mountedInstance);
- expect(autoBound.call(context)).toBe(mountedInstance);
-
- expect(explicitlyBound.call(mountedInstance)).toBe(mountedInstance);
- expect(autoBound.call(mountedInstance)).toBe(mountedInstance);
-
- });
-
- it('should not pass this to getDefaultProps', () => {
- var Component = React.createClass({
- getDefaultProps: function() {
- expect(this.render).not.toBeDefined();
- return {};
- },
- render: function() {
- return ;
- },
- });
- ReactTestUtils.renderIntoDocument();
- });
-
it('should use default values for undefined props', () => {
class Component extends React.Component {
static defaultProps = {prop: 'testKey'};
@@ -1178,17 +1119,17 @@ describe('ReactCompositeComponent', () => {
});
it('should replace state', () => {
- var Moo = React.createClass({
- getInitialState: function() {
- return {x: 1};
- },
- render: function() {
+ class Moo extends React.Component {
+ state = {x: 1};
+ render() {
return ;
- },
- });
+ }
+ }
var moo = ReactTestUtils.renderIntoDocument();
- moo.replaceState({y: 2});
+ // No longer a public API, but we can test that it works internally by
+ // reaching into the updater.
+ moo.updater.enqueueReplaceState(moo, {y: 2});
expect('x' in moo.state).toBe(false);
expect(moo.state.y).toBe(2);
});
@@ -1200,21 +1141,22 @@ describe('ReactCompositeComponent', () => {
NotActuallyImmutable.prototype.amIImmutable = function() {
return true;
};
- var Moo = React.createClass({
- getInitialState: function() {
- return new NotActuallyImmutable('first');
- },
- render: function() {
+ class Moo extends React.Component {
+ state = new NotActuallyImmutable('first');
+ // No longer a public API, but we can test that it works internally by
+ // reaching into the updater.
+ _replaceState = update => this.updater.enqueueReplaceState(this, update);
+ render() {
return ;
- },
- });
+ }
+ }
var moo = ReactTestUtils.renderIntoDocument();
expect(moo.state.str).toBe('first');
expect(moo.state.amIImmutable()).toBe(true);
var secondState = new NotActuallyImmutable('second');
- moo.replaceState(secondState);
+ moo._replaceState(secondState);
expect(moo.state.str).toBe('second');
expect(moo.state.amIImmutable()).toBe(true);
expect(moo.state).toBe(secondState);
@@ -1228,14 +1170,14 @@ describe('ReactCompositeComponent', () => {
var fifthState = new NotActuallyImmutable('fifth');
ReactUpdates.batchedUpdates(function() {
moo.setState({str: 'fourth'});
- moo.replaceState(fifthState);
+ moo._replaceState(fifthState);
});
expect(moo.state).toBe(fifthState);
// When more than one state update is enqueued, we have the same behavior
var sixthState = new NotActuallyImmutable('sixth');
ReactUpdates.batchedUpdates(function() {
- moo.replaceState(sixthState);
+ moo._replaceState(sixthState);
moo.setState({str: 'seventh'});
});
expect(moo.state.str).toBe('seventh');
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js
index c758aa5d2e665..3385d7a4d5276 100644
--- a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js
@@ -23,34 +23,34 @@ describe('ReactCompositeComponent-state', () => {
ReactDOM = require('ReactDOM');
- TestComponent = React.createClass({
- peekAtState: function(from, state) {
- state = state || this.state;
- this.props.stateListener(from, state && state.color);
- },
+ TestComponent = class extends React.Component {
+ constructor(props) {
+ super(props);
+ this.peekAtState('getInitialState', undefined, props);
+ this.state = {color: 'red'};
+ }
+
+ peekAtState = (from, state = this.state, props = this.props) => {
+ props.stateListener(from, state && state.color);
+ }
- peekAtCallback: function(from) {
+ peekAtCallback = from => {
return () => this.peekAtState(from);
- },
+ }
- setFavoriteColor: function(nextColor) {
+ setFavoriteColor(nextColor) {
this.setState(
{color: nextColor},
this.peekAtCallback('setFavoriteColor')
);
- },
-
- getInitialState: function() {
- this.peekAtState('getInitialState');
- return {color: 'red'};
- },
+ }
- render: function() {
+ render() {
this.peekAtState('render');
return {this.state.color}
;
- },
+ }
- componentWillMount: function() {
+ componentWillMount() {
this.peekAtState('componentWillMount-start');
this.setState(function(state) {
this.peekAtState('before-setState-sunrise', state);
@@ -71,25 +71,27 @@ describe('ReactCompositeComponent-state', () => {
this.peekAtState('after-setState-orange', state);
});
this.peekAtState('componentWillMount-end');
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this.peekAtState('componentDidMount-start');
this.setState(
{color: 'yellow'},
this.peekAtCallback('setState-yellow')
);
this.peekAtState('componentDidMount-end');
- },
+ }
- componentWillReceiveProps: function(newProps) {
+ componentWillReceiveProps(newProps) {
this.peekAtState('componentWillReceiveProps-start');
if (newProps.nextColor) {
this.setState(function(state) {
this.peekAtState('before-setState-receiveProps', state);
return {color: newProps.nextColor};
});
- this.replaceState({color: undefined});
+ // No longer a public API, but we can test that it works internally by
+ // reaching into the updater.
+ this.updater.enqueueReplaceState(this, {color: undefined});
this.setState(
function(state) {
this.peekAtState('before-setState-again-receiveProps', state);
@@ -102,28 +104,28 @@ describe('ReactCompositeComponent-state', () => {
});
}
this.peekAtState('componentWillReceiveProps-end');
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
this.peekAtState('shouldComponentUpdate-currentState');
this.peekAtState('shouldComponentUpdate-nextState', nextState);
return true;
- },
+ }
- componentWillUpdate: function(nextProps, nextState) {
+ componentWillUpdate(nextProps, nextState) {
this.peekAtState('componentWillUpdate-currentState');
this.peekAtState('componentWillUpdate-nextState', nextState);
- },
+ }
- componentDidUpdate: function(prevProps, prevState) {
+ componentDidUpdate(prevProps, prevState) {
this.peekAtState('componentDidUpdate-currentState');
this.peekAtState('componentDidUpdate-prevState', prevState);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this.peekAtState('componentWillUnmount');
- },
- });
+ }
+ };
});
it('should support setting state', () => {
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js
index 4fa299e3fda22..4d9bffc425165 100644
--- a/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js
@@ -33,14 +33,14 @@ describe('ReactMultiChild', () => {
var mockUpdate = jest.fn();
var mockUnmount = jest.fn();
- var MockComponent = React.createClass({
- componentDidMount: mockMount,
- componentDidUpdate: mockUpdate,
- componentWillUnmount: mockUnmount,
- render: function() {
+ class MockComponent extends React.Component {
+ componentDidMount = mockMount;
+ componentDidUpdate = mockUpdate;
+ componentWillUnmount = mockUnmount;
+ render() {
return ;
- },
- });
+ }
+ }
expect(mockMount.mock.calls.length).toBe(0);
expect(mockUpdate.mock.calls.length).toBe(0);
@@ -65,13 +65,13 @@ describe('ReactMultiChild', () => {
var mockMount = jest.fn();
var mockUnmount = jest.fn();
- var MockComponent = React.createClass({
- componentDidMount: mockMount,
- componentWillUnmount: mockUnmount,
- render: function() {
+ class MockComponent extends React.Component {
+ componentDidMount = mockMount;
+ componentWillUnmount = mockUnmount;
+ render() {
return ;
- },
- });
+ }
+ }
expect(mockMount.mock.calls.length).toBe(0);
expect(mockUnmount.mock.calls.length).toBe(0);
@@ -93,13 +93,13 @@ describe('ReactMultiChild', () => {
var mockMount = jest.fn();
var mockUnmount = jest.fn();
- var MockComponent = React.createClass({
- componentDidMount: mockMount,
- componentWillUnmount: mockUnmount,
- render: function() {
+ class MockComponent extends React.Component {
+ componentDidMount = mockMount;
+ componentWillUnmount = mockUnmount;
+ render() {
return ;
- },
- });
+ }
+ }
class WrapperComponent extends React.Component {
render() {
@@ -130,13 +130,13 @@ describe('ReactMultiChild', () => {
var mockMount = jest.fn();
var mockUnmount = jest.fn();
- var MockComponent = React.createClass({
- componentDidMount: mockMount,
- componentWillUnmount: mockUnmount,
- render: function() {
+ class MockComponent extends React.Component {
+ componentDidMount = mockMount;
+ componentWillUnmount = mockUnmount;
+ render() {
return ;
- },
- });
+ }
+ }
expect(mockMount.mock.calls.length).toBe(0);
expect(mockUnmount.mock.calls.length).toBe(0);
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactStateSetters-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactStateSetters-test.js
deleted file mode 100644
index c813dfe09c40e..0000000000000
--- a/src/renderers/shared/stack/reconciler/__tests__/ReactStateSetters-test.js
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React = require('React');
-var ReactStateSetters = require('ReactStateSetters');
-var ReactTestUtils = require('ReactTestUtils');
-
-var TestComponent;
-var TestComponentWithMixin;
-
-describe('ReactStateSetters', () => {
- beforeEach(() => {
- jest.resetModuleRegistry();
-
- TestComponent = class extends React.Component {
- state = {foo: 'foo'};
-
- render() {
- return ;
- }
- };
-
- TestComponentWithMixin = React.createClass({
- mixins: [ReactStateSetters.Mixin],
-
- getInitialState: function() {
- return {foo: 'foo'};
- },
-
- render: function() {
- return ;
- },
- });
- });
-
- it('createStateSetter should update state', () => {
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'foo'});
-
- var setter = ReactStateSetters.createStateSetter(
- instance,
- function(a, b, c) {
- return {
- foo: a + b + c,
- bar: a * b * c,
- };
- }
- );
- expect(instance.state).toEqual({foo: 'foo'});
-
- setter(1, 2, 3);
- expect(instance.state).toEqual({foo: 6, bar: 6});
-
- setter(10, 11, 12);
- expect(instance.state).toEqual({foo: 33, bar: 1320});
- });
-
- it('createStateKeySetter should update state', () => {
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'foo'});
-
- var setter = ReactStateSetters.createStateKeySetter(instance, 'foo');
-
- expect(instance.state).toEqual({foo: 'foo'});
-
- setter('bar');
- expect(instance.state).toEqual({foo: 'bar'});
-
- setter('baz');
- expect(instance.state).toEqual({foo: 'baz'});
- });
-
- it('createStateKeySetter is memoized', () => {
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'foo'});
-
- var foo1 = ReactStateSetters.createStateKeySetter(instance, 'foo');
- var bar1 = ReactStateSetters.createStateKeySetter(instance, 'bar');
-
- var foo2 = ReactStateSetters.createStateKeySetter(instance, 'foo');
- var bar2 = ReactStateSetters.createStateKeySetter(instance, 'bar');
-
- expect(foo2).toBe(foo1);
- expect(bar2).toBe(bar1);
- });
-
- it('createStateSetter should update state from mixin', () => {
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'foo'});
-
- var setter = instance.createStateSetter(
- function(a, b, c) {
- return {
- foo: a + b + c,
- bar: a * b * c,
- };
- }
- );
- expect(instance.state).toEqual({foo: 'foo'});
-
- setter(1, 2, 3);
- expect(instance.state).toEqual({foo: 6, bar: 6});
-
- setter(10, 11, 12);
- expect(instance.state).toEqual({foo: 33, bar: 1320});
- });
-
- it('createStateKeySetter should update state with mixin', () => {
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'foo'});
-
- var setter = instance.createStateKeySetter('foo');
-
- expect(instance.state).toEqual({foo: 'foo'});
-
- setter('bar');
- expect(instance.state).toEqual({foo: 'bar'});
-
- setter('baz');
- expect(instance.state).toEqual({foo: 'baz'});
- });
-
- it('createStateKeySetter is memoized with mixin', () => {
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'foo'});
-
- var foo1 = instance.createStateKeySetter('foo');
- var bar1 = instance.createStateKeySetter('bar');
-
- var foo2 = instance.createStateKeySetter('foo');
- var bar2 = instance.createStateKeySetter('bar');
-
- expect(foo2).toBe(foo1);
- expect(bar2).toBe(bar1);
- });
-});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js
index 044e709b4b382..026a938eb24d2 100644
--- a/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js
@@ -391,30 +391,23 @@ describe('ReactUpdates', () => {
},
};
- var Box = React.createClass({
- mixins: [UpdateLoggingMixin],
-
- render: function() {
+ class Box extends React.Component {
+ render() {
return {this.props.children}
;
- },
- });
-
- var Child = React.createClass({
- mixins: [UpdateLoggingMixin],
+ }
+ }
+ Object.assign(Box.prototype, UpdateLoggingMixin);
- render: function() {
+ class Child extends React.Component {
+ render() {
return child;
- },
- });
-
- var Switcher = React.createClass({
- mixins: [UpdateLoggingMixin],
-
- getInitialState: function() {
- return {tabKey: 'hello'};
- },
+ }
+ }
+ Object.assign(Child.prototype, UpdateLoggingMixin);
- render: function() {
+ class Switcher extends React.Component {
+ state = {tabKey: 'hello'};
+ render() {
var child = this.props.children;
return (
@@ -428,20 +421,20 @@ describe('ReactUpdates', () => {
);
- },
- });
-
- var App = React.createClass({
- mixins: [UpdateLoggingMixin],
+ }
+ }
+ Object.assign(Switcher.prototype, UpdateLoggingMixin);
- render: function() {
+ class App extends React.Component {
+ render() {
return (
);
- },
- });
+ }
+ }
+ Object.assign(App.prototype, UpdateLoggingMixin);
var root = ;
root = ReactTestUtils.renderIntoDocument(root);
@@ -988,35 +981,6 @@ describe('ReactUpdates', () => {
);
});
- it('throws in replaceState if the update callback is not a function', () => {
- function Foo() {
- this.a = 1;
- this.b = 2;
- }
- var A = React.createClass({
- getInitialState: function() {
- return {};
- },
- render: function() {
- return ;
- },
- });
- var component = ReactTestUtils.renderIntoDocument();
-
- expect(() => component.replaceState({}, 'no')).toThrowError(
- 'replaceState(...): Expected the last optional `callback` argument ' +
- 'to be a function. Instead received: string.'
- );
- expect(() => component.replaceState({}, {})).toThrowError(
- 'replaceState(...): Expected the last optional `callback` argument ' +
- 'to be a function. Instead received: Object.'
- );
- expect(() => component.replaceState({}, new Foo())).toThrowError(
- 'replaceState(...): Expected the last optional `callback` argument ' +
- 'to be a function. Instead received: Foo (keys: a, b).'
- );
- });
-
it('throws in forceUpdate if the update callback is not a function', () => {
function Foo() {
this.a = 1;
diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js
index fa202e7e9d8eb..f63200f6fd741 100644
--- a/src/test/__tests__/ReactTestUtils-test.js
+++ b/src/test/__tests__/ReactTestUtils-test.js
@@ -91,12 +91,12 @@ describe('ReactTestUtils', () => {
it('should have shallow unmounting', () => {
var componentWillUnmount = jest.fn();
- var SomeComponent = React.createClass({
- render: function() {
+ class SomeComponent extends React.Component {
+ componentWillUnmount = componentWillUnmount;
+ render() {
return ;
- },
- componentWillUnmount,
- });
+ }
+ }
var shallowRenderer = ReactTestUtils.createRenderer();
shallowRenderer.render();
diff --git a/yarn.lock b/yarn.lock
index 240e586d2d610..bf09363a81aa6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2060,6 +2060,18 @@ fbjs@^0.8.5:
promise "^7.1.1"
ua-parser-js "^0.7.9"
+fbjs@^0.8.9:
+ version "0.8.9"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14"
+ dependencies:
+ core-js "^1.0.0"
+ isomorphic-fetch "^2.1.1"
+ loose-envify "^1.0.0"
+ object-assign "^4.1.0"
+ promise "^7.1.1"
+ setimmediate "^1.0.5"
+ ua-parser-js "^0.7.9"
+
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -3930,11 +3942,7 @@ object-assign@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
-object-assign@^4.0.1, object-assign@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
-
-object-assign@^4.1.1:
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -4257,6 +4265,13 @@ rc@~1.1.6:
minimist "^1.2.0"
strip-json-comments "~1.0.4"
+react-create-class@15.5.0-alpha.2:
+ version "15.5.0-alpha.2"
+ resolved "https://registry.yarnpkg.com/react-create-class/-/react-create-class-15.5.0-alpha.2.tgz#b6e55133ecebc95cc0eb0a9a0acf1679a86b02d4"
+ dependencies:
+ fbjs "^0.8.9"
+ object-assign "^4.1.1"
+
read-only-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0"
@@ -4585,6 +4600,10 @@ set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+setimmediate@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
sha.js@^2.3.6, sha.js@~2.4.4:
version "2.4.8"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"