diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index f10de36d2e98f..a522d2c65ace2 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -12,15 +12,16 @@ 'use strict'; var ReactChildren = require('ReactChildren'); +var ReactClass = require('ReactClass'); var ReactComponent = require('ReactComponent'); var ReactPureComponent = require('ReactPureComponent'); -var ReactClass = require('ReactClass'); var ReactDOMFactories = require('ReactDOMFactories'); var ReactElement = require('ReactElement'); var ReactPropTypes = require('ReactPropTypes'); var ReactVersion = require('ReactVersion'); var onlyChild = require('onlyChild'); +var warning = require('warning'); var createElement = ReactElement.createElement; var createFactory = ReactElement.createFactory; @@ -55,16 +56,6 @@ if (__DEV__) { warnedForSpread = true; return Object.assign.apply(null, arguments); }; - - createMixin = function(mixin) { - lowPriorityWarning( - warnedForCreateMixin, - 'React.createMixin is deprecated and should not be used. You ' + - 'can use this mixin directly instead.', - ); - warnedForCreateMixin = true; - return mixin; - }; } var React = { @@ -102,8 +93,9 @@ var React = { __spread: __spread, }; -// TODO: Fix tests so that this deprecation warning doesn't cause failures. if (__DEV__) { + let warnedForCreateMixin = false; + let warnedForCreateClass = false; if (canDefineProperty) { Object.defineProperty(React, 'PropTypes', { get() { @@ -127,7 +119,7 @@ if (__DEV__) { 'drop-in replacement.', ); didWarnPropTypesDeprecated = true; - return ReactPropTypes; + return ReactClass.createClass; }, }); } diff --git a/src/isomorphic/classic/class/__tests__/ReactClass-test.js b/src/isomorphic/classic/class/__tests__/ReactClass-test.js deleted file mode 100644 index 17fa24e6776bc..0000000000000 --- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js +++ /dev/null @@ -1,372 +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 ReactTestUtils; -var PropTypes; - -describe('ReactClass-spec', () => { - beforeEach(() => { - React = require('React'); - ReactDOM = require('ReactDOM'); - ReactTestUtils = require('ReactTestUtils'); - PropTypes = require('prop-types'); - }); - - it('should warn on first call to React.createClass', () => { - spyOn(console, 'error'); - const spec = { - displayName: 'MyComponent', - 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: MyComponent: React.createClass is deprecated and will be removed in ' + - "version 16. Use plain JavaScript classes instead. If you're not yet " + - 'ready to migrate, create-react-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({}); - }).toThrowError( - 'createClass(...): Class specification must implement a `render` method.', - ); - }); - - it('should copy `displayName` onto the Constructor', () => { - var TestComponent = React.createClass({ - render: function() { - return
; - }, - }); - - expect(TestComponent.displayName).toBe('TestComponent'); - }); - - it('should copy prop types onto the Constructor', () => { - var propValidator = jest.fn(); - var TestComponent = React.createClass({ - propTypes: { - value: propValidator, - }, - render: function() { - return
; - }, - }); - - expect(TestComponent.propTypes).toBeDefined(); - expect(TestComponent.propTypes.value).toBe(propValidator); - }); - - it('should warn on invalid prop types', () => { - spyOn(console, 'error'); - React.createClass({ - displayName: 'Component', - propTypes: { - prop: null, - }, - render: function() { - return {this.props.prop}; - }, - }); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component: prop type `prop` is invalid; ' + - 'it must be a function, usually from React.PropTypes.', - ); - }); - - it('should warn on invalid context types', () => { - spyOn(console, 'error'); - React.createClass({ - displayName: 'Component', - contextTypes: { - prop: null, - }, - render: function() { - return {this.props.prop}; - }, - }); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component: context type `prop` is invalid; ' + - 'it must be a function, usually from React.PropTypes.', - ); - }); - - it('should throw on invalid child context types', () => { - spyOn(console, 'error'); - React.createClass({ - displayName: 'Component', - childContextTypes: { - prop: null, - }, - render: function() { - return {this.props.prop}; - }, - }); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component: child context type `prop` is invalid; ' + - 'it must be a function, usually from React.PropTypes.', - ); - }); - - it('should warn when mispelling shouldComponentUpdate', () => { - spyOn(console, 'error'); - - React.createClass({ - componentShouldUpdate: function() { - return false; - }, - render: function() { - return
; - }, - }); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: A component 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.', - ); - - React.createClass({ - displayName: 'NamedComponent', - componentShouldUpdate: function() { - return false; - }, - render: function() { - return
; - }, - }); - expect(console.error.calls.count()).toBe(2); - expect(console.error.calls.argsFor(1)[0]).toBe( - 'Warning: NamedComponent 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.', - ); - }); - - it('should warn when mispelling componentWillReceiveProps', () => { - spyOn(console, 'error'); - React.createClass({ - componentWillRecieveProps: function() { - return false; - }, - render: function() { - return
; - }, - }); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: A component has a method called componentWillRecieveProps(). Did you ' + - 'mean componentWillReceiveProps()?', - ); - }); - - it('should throw if a reserved property is in statics', () => { - expect(function() { - React.createClass({ - statics: { - getDefaultProps: function() { - return { - foo: 0, - }; - }, - }, - - render: function() { - return ; - }, - }); - }).toThrowError( - 'ReactClass: You are attempting to define a reserved property, ' + - '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' + - 'it as an instance property instead; it will still be accessible on ' + - 'the constructor.', - ); - }); - - // TODO: Consider actually moving these to statics or drop this unit test. - - xit('should warn when using deprecated non-static spec keys', () => { - spyOn(console, 'error'); - React.createClass({ - mixins: [{}], - propTypes: { - foo: PropTypes.string, - }, - contextTypes: { - foo: PropTypes.string, - }, - childContextTypes: { - foo: PropTypes.string, - }, - render: function() { - return
; - }, - }); - expect(console.error.calls.count()).toBe(4); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'createClass(...): `mixins` is now a static property and should ' + - 'be defined inside "statics".', - ); - expect(console.error.calls.argsFor(1)[0]).toBe( - 'createClass(...): `propTypes` is now a static property and should ' + - 'be defined inside "statics".', - ); - expect(console.error.calls.argsFor(2)[0]).toBe( - 'createClass(...): `contextTypes` is now a static property and ' + - 'should be defined inside "statics".', - ); - expect(console.error.calls.argsFor(3)[0]).toBe( - 'createClass(...): `childContextTypes` is now a static property and ' + - 'should be defined inside "statics".', - ); - }); - - it('should support statics', () => { - var Component = React.createClass({ - statics: { - abc: 'def', - def: 0, - ghi: null, - jkl: 'mno', - pqr: function() { - return this; - }, - }, - - render: function() { - return ; - }, - }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - expect(instance.constructor.abc).toBe('def'); - expect(Component.abc).toBe('def'); - expect(instance.constructor.def).toBe(0); - expect(Component.def).toBe(0); - expect(instance.constructor.ghi).toBe(null); - expect(Component.ghi).toBe(null); - expect(instance.constructor.jkl).toBe('mno'); - expect(Component.jkl).toBe('mno'); - expect(instance.constructor.pqr()).toBe(Component); - expect(Component.pqr()).toBe(Component); - }); - - it('should work with object getInitialState() return values', () => { - var Component = React.createClass({ - getInitialState: function() { - return { - occupation: 'clown', - }; - }, - render: function() { - return ; - }, - }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - expect(instance.state.occupation).toEqual('clown'); - }); - - it('renders based on context getInitialState', () => { - var Foo = React.createClass({ - contextTypes: { - className: PropTypes.string, - }, - getInitialState() { - return {className: this.context.className}; - }, - render() { - return ; - }, - }); - - var Outer = React.createClass({ - childContextTypes: { - className: PropTypes.string, - }, - getChildContext() { - return {className: 'foo'}; - }, - render() { - return ; - }, - }); - - var container = document.createElement('div'); - ReactDOM.render(, container); - expect(container.firstChild.className).toBe('foo'); - }); - - it('should throw with non-object getInitialState() return values', () => { - [['an array'], 'a string', 1234].forEach(function(state) { - var Component = React.createClass({ - getInitialState: function() { - return state; - }, - render: function() { - return ; - }, - }); - var instance = ; - expect(function() { - instance = ReactTestUtils.renderIntoDocument(instance); - }).toThrowError( - 'Component.getInitialState(): must return an object or null', - ); - }); - }); - - it('should work with a null getInitialState() return value', () => { - var Component = React.createClass({ - getInitialState: function() { - return null; - }, - render: function() { - return ; - }, - }); - expect(() => - ReactTestUtils.renderIntoDocument(), - ).not.toThrow(); - }); - - it('should throw when using legacy factories', () => { - spyOn(console, 'error'); - var Component = React.createClass({ - render() { - return
; - }, - }); - - expect(() => Component()).toThrow(); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Something is calling a React component directly. Use a ' + - 'factory or JSX instead. See: https://fb.me/react-legacyfactory', - ); - }); -}); diff --git a/src/isomorphic/classic/class/createClass.js b/src/isomorphic/classic/class/createClass.js new file mode 100644 index 0000000000000..3791e5392dc0a --- /dev/null +++ b/src/isomorphic/classic/class/createClass.js @@ -0,0 +1,19 @@ +/** + * 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. + * + * @providesModule createClass + */ + +'use strict'; + +var {Component} = require('ReactBaseClasses'); +var {isValidElement} = require('ReactElement'); +var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); +var factory = require('create-react-class/factory'); + +module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue); diff --git a/src/renderers/art/ReactART.js b/src/renderers/art/ReactART.js index b2d977a3ae569..5ba69018e948c 100644 --- a/src/renderers/art/ReactART.js +++ b/src/renderers/art/ReactART.js @@ -171,12 +171,8 @@ const ContainerMixin = assign({}, ReactMultiChild.Mixin, { // Surface is a React DOM Component, not an ART component. It serves as the // entry point into the ART reconciler. -const Surface = React.createClass({ - displayName: 'Surface', - - mixins: [ContainerMixin], - - componentDidMount: function() { +class Surface extends React.Component { + componentDidMount() { const domNode = ReactDOM.findDOMNode(this); this.node = Mode.Surface(+this.props.width, +this.props.height, domNode); @@ -190,9 +186,9 @@ const Surface = React.createClass({ ReactInstanceMap.get(this)._context, ); ReactUpdates.ReactReconcileTransaction.release(transaction); - }, + } - componentDidUpdate: function(oldProps) { + componentDidUpdate(oldProps) { const node = this.node; if ( this.props.width != oldProps.width || @@ -214,13 +210,13 @@ const Surface = React.createClass({ if (node.render) { node.render(); } - }, + } - componentWillUnmount: function() { + componentWillUnmount() { this.unmountChildren(); - }, + } - render: function() { + render() { // This is going to be a placeholder because we don't know what it will // actually resolve to because ART may render canvas, vml or svg tags here. // We only allow a subset of properties since others might conflict with @@ -238,8 +234,8 @@ const Surface = React.createClass({ title={props.title} /> ); - }, -}); + } +} // Various nodes that can go into a surface diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js index 59eaec42bfc66..03dbda5dcc40d 100644 --- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js @@ -1089,22 +1089,20 @@ describe('ReactDOMInput', () => { describe('assigning the value attribute on controlled inputs', function() { function getTestInput() { - return React.createClass({ - getInitialState: function() { - return { - value: this.props.value == null ? '' : this.props.value, - }; - }, - onChange: function(event) { + return class extends React.Component { + state = { + value: this.props.value == null ? '' : this.props.value, + }; + onChange = event => { this.setState({value: event.target.value}); - }, - render: function() { + }; + render() { var type = this.props.type; var value = this.state.value; return ; - }, - }); + } + }; } it('always sets the attribute when values change on text inputs', function() {