From a8d37a7aa0033d1af9eb886509a96f778881fe12 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Apr 2017 15:23:28 +0100 Subject: [PATCH 01/43] Remove indirection in checking propTypes (#9358) * Remove indirection in checking propTypes * Silence flow errors --- .../classic/element/ReactElementValidator.js | 11 +++++--- .../types/__tests__/ReactPropTypes-test.js | 4 +-- .../shared/fiber/ReactFiberContext.js | 20 +++++++++++--- .../reconciler/ReactCompositeComponent.js | 9 +++++-- src/shared/types/checkReactTypeSpec.js | 26 ------------------- 5 files changed, 33 insertions(+), 37 deletions(-) delete mode 100644 src/shared/types/checkReactTypeSpec.js diff --git a/src/isomorphic/classic/element/ReactElementValidator.js b/src/isomorphic/classic/element/ReactElementValidator.js index 324433338385b..9840ba3a59bb8 100644 --- a/src/isomorphic/classic/element/ReactElementValidator.js +++ b/src/isomorphic/classic/element/ReactElementValidator.js @@ -21,13 +21,12 @@ var ReactCurrentOwner = require('ReactCurrentOwner'); var ReactElement = require('ReactElement'); -var checkReactTypeSpec = require('checkReactTypeSpec'); - var canDefineProperty = require('canDefineProperty'); var getComponentName = require('getComponentName'); var getIteratorFn = require('getIteratorFn'); if (__DEV__) { + var checkPropTypes = require('checkPropTypes'); var warning = require('fbjs/lib/warning'); var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame'); var { @@ -193,7 +192,13 @@ function validatePropTypes(element) { : componentClass.propTypes; if (propTypes) { - checkReactTypeSpec(propTypes, element.props, 'prop', name); + checkPropTypes( + propTypes, + element.props, + 'prop', + name, + ReactDebugCurrentFrame.getStackAddendum, + ); } if (typeof componentClass.getDefaultProps === 'function') { warning( diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 74059935308c9..edcaca7a6f9a0 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -13,7 +13,6 @@ var PropTypes; var checkPropTypes; -var checkReactTypeSpec; var React; var ReactDOM; @@ -22,7 +21,6 @@ var MyComponent; function resetWarningCache() { jest.resetModules(); - checkReactTypeSpec = require('checkReactTypeSpec'); checkPropTypes = require('checkPropTypes'); } @@ -33,7 +31,7 @@ function getPropTypeWarningMessage(propTypes, object, componentName) { console.error.calls.reset(); } resetWarningCache(); - checkReactTypeSpec(propTypes, object, 'prop', 'testComponent'); + checkPropTypes(propTypes, object, 'prop', 'testComponent'); const callCount = console.error.calls.count(); if (callCount > 1) { throw new Error('Too many warnings.'); diff --git a/src/renderers/shared/fiber/ReactFiberContext.js b/src/renderers/shared/fiber/ReactFiberContext.js index 0f45d75323ff9..67f37d1776162 100644 --- a/src/renderers/shared/fiber/ReactFiberContext.js +++ b/src/renderers/shared/fiber/ReactFiberContext.js @@ -15,6 +15,7 @@ import type {Fiber} from 'ReactFiber'; import type {StackCursor} from 'ReactFiberStack'; +var React = require('react'); var emptyObject = require('fbjs/lib/emptyObject'); var getComponentName = require('getComponentName'); var invariant = require('fbjs/lib/invariant'); @@ -33,7 +34,6 @@ const { } = require('ReactFiberStack'); if (__DEV__) { - var checkReactTypeSpec = require('checkReactTypeSpec'); var ReactDebugCurrentFrame = require('react/lib/ReactDebugCurrentFrame'); var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber'); var { @@ -105,7 +105,14 @@ exports.getMaskedContext = function( if (__DEV__) { const name = getComponentName(workInProgress) || 'Unknown'; ReactDebugCurrentFrame.current = workInProgress; - checkReactTypeSpec(contextTypes, context, 'context', name); + // $FlowFixMe - We know this export exists now, need to wait for Flow update + React.checkPropTypes( + contextTypes, + context, + 'context', + name, + ReactDebugCurrentFrame.getStackAddendum, + ); ReactDebugCurrentFrame.current = null; } @@ -212,7 +219,14 @@ function processChildContext( // TODO: remove this hack when we delete unstable_renderSubtree in Fiber. const workInProgress = isReconciling ? fiber : null; ReactDebugCurrentFrame.current = workInProgress; - checkReactTypeSpec(childContextTypes, childContext, 'child context', name); + // $FlowFixMe - We know this export exists now, need to wait for Flow update + React.checkPropTypes( + childContextTypes, + childContext, + 'child context', + name, + ReactDebugCurrentFrame.getStackAddendum, + ); ReactDebugCurrentFrame.current = null; } diff --git a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js index 5dfcc45d440c3..d2217db557af9 100644 --- a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js @@ -23,7 +23,6 @@ var ReactNodeTypes = require('ReactNodeTypes'); var ReactReconciler = require('ReactReconciler'); if (__DEV__) { - var checkReactTypeSpec = require('checkReactTypeSpec'); var ReactDebugCurrentFrame = require('react/lib/ReactDebugCurrentFrame'); var warningAboutMissingGetChildContext = {}; } @@ -730,7 +729,13 @@ var ReactCompositeComponent = { _checkContextTypes: function(typeSpecs, values, location: string) { if (__DEV__) { ReactDebugCurrentFrame.current = this._debugID; - checkReactTypeSpec(typeSpecs, values, location, this.getName()); + React.checkPropTypes( + typeSpecs, + values, + location, + this.getName(), + ReactDebugCurrentFrame.getStackAddendum, + ); ReactDebugCurrentFrame.current = null; } }, diff --git a/src/shared/types/checkReactTypeSpec.js b/src/shared/types/checkReactTypeSpec.js deleted file mode 100644 index 131e23e1a5f8b..0000000000000 --- a/src/shared/types/checkReactTypeSpec.js +++ /dev/null @@ -1,26 +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. - * - * @providesModule checkReactTypeSpec - */ - -'use strict'; - -var checkPropTypes = require('react/lib/checkPropTypes'); -var {getStackAddendum} = require('react/lib/ReactDebugCurrentFrame'); - -function checkReactTypeSpec( - typeSpecs, - values, - location: string, - componentName, -) { - checkPropTypes(typeSpecs, values, location, componentName, getStackAddendum); -} - -module.exports = checkReactTypeSpec; From e303e00d065c2da9b6acec07ebc85337cba3f442 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Apr 2017 16:17:36 +0100 Subject: [PATCH 02/43] Tweak Rollup setup (#9364) * Remove unused Rollup shim and exports * Add a way to build multiple bundles --- scripts/rollup/build.js | 32 +++++++++++++++++++++-------- scripts/rollup/modules.js | 33 ------------------------------ scripts/rollup/results.json | 40 ++++++++++++++++++------------------- 3 files changed, 44 insertions(+), 61 deletions(-) diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 30d8d29e9a874..b557a11926504 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -31,8 +31,12 @@ const RN_DEV = Bundles.bundleTypes.RN_DEV; const RN_PROD = Bundles.bundleTypes.RN_PROD; const reactVersion = require('../../package.json').version; -const inputBundleType = argv.type; -const inputBundleName = argv._ && argv._[0]; +const requestedBundleTypes = (argv.type || '') + .split(',') + .map(type => type.toUpperCase()); +const requestedBundleNames = (argv._[0] || '') + .split(',') + .map(type => type.toLowerCase()); // used for when we property mangle with uglify/gcc const mangleRegex = new RegExp( @@ -294,14 +298,26 @@ function getPlugins( } function createBundle(bundle, bundleType) { - if ( - (inputBundleType && bundleType.indexOf(inputBundleType) === -1) || - bundle.bundleTypes.indexOf(bundleType) === -1 || - (inputBundleName && bundle.label.indexOf(inputBundleName) === -1) - ) { - // Skip this bundle because its config doesn't specify this target. + const shouldSkipBundleType = bundle.bundleTypes.indexOf(bundleType) === -1; + if (shouldSkipBundleType) { return Promise.resolve(); } + if (requestedBundleTypes.length > 0) { + const isAskingForDifferentType = requestedBundleTypes.every( + requestedType => bundleType.indexOf(requestedType) === -1 + ); + if (isAskingForDifferentType) { + return Promise.resolve(); + } + } + if (requestedBundleNames.length > 0) { + const isAskingForDifferentNames = requestedBundleNames.every( + requestedName => bundle.label.indexOf(requestedName) === -1 + ); + if (isAskingForDifferentNames) { + return Promise.resolve(); + } + } const filename = getFilename(bundle.name, bundle.hasteName, bundleType); const logKey = chalk.white.bold(filename) + diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index 2be3391469332..832e19b05c62e 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -255,28 +255,6 @@ function getReactCurrentOwnerModuleAlias(bundleType, isRenderer) { } } -// this works almost identically to the ReactCurrentOwner shim above -const shimReactCheckPropTypes = resolve( - './scripts/rollup/shims/rollup/ReactCheckPropTypesRollupShim.js' -); -const realCheckPropTypes = resolve( - './src/isomorphic/classic/types/checkPropTypes.js' -); - -function getReactCheckPropTypesModuleAlias(bundleType, isRenderer) { - if (isRenderer) { - return { - checkPropTypes: shimReactCheckPropTypes, - 'react/lib/checkPropTypes': shimReactCheckPropTypes, - }; - } else { - return { - checkPropTypes: realCheckPropTypes, - 'react/lib/checkPropTypes': realCheckPropTypes, - }; - } -} - // this works almost identically to the ReactCurrentOwner shim above const shimReactComponentTreeHook = resolve( './scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js' @@ -323,7 +301,6 @@ function replaceDevOnlyStubbedModules(bundleType) { function getAliases(paths, bundleType, isRenderer, extractErrors) { return Object.assign( getReactCurrentOwnerModuleAlias(bundleType, isRenderer), - getReactCheckPropTypesModuleAlias(bundleType, isRenderer), getReactComponentTreeHookModuleAlias(bundleType, isRenderer), createModuleMap( paths, @@ -353,17 +330,7 @@ module.exports = { getExcludedHasteGlobs, getDefaultReplaceModules, getAliases, - createModuleMap, - getNodeModules, - replaceInternalModules, - getInternalModules, - getFbjsModuleAliases, - replaceFbjsModuleAliases, ignoreFBModules, ignoreReactNativeModules, getExternalModules, - getReactCurrentOwnerModuleAlias, - getReactCheckPropTypesModuleAlias, - getReactComponentTreeHookModuleAlias, - replaceDevOnlyStubbedModules, }; diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index f2b0466682d6b..18e29d0eae1f4 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -2,24 +2,24 @@ "branch": "master", "bundleSizes": { "react.development.js (UMD_DEV)": { - "size": 116402, - "gzip": 29598 + "size": 116208, + "gzip": 29564 }, "react.production.min.js (UMD_PROD)": { "size": 13719, "gzip": 5080 }, "react-dom.development.js (UMD_DEV)": { - "size": 564925, - "gzip": 130471 + "size": 564771, + "gzip": 130439 }, "react-dom.production.min.js (UMD_PROD)": { "size": 120123, "gzip": 37844 }, "react-dom-server.development.js (UMD_DEV)": { - "size": 477377, - "gzip": 115561 + "size": 477021, + "gzip": 115494 }, "react-dom-server.production.min.js (UMD_PROD)": { "size": 106349, @@ -34,56 +34,56 @@ "gzip": 28976 }, "react.development.js (NODE_DEV)": { - "size": 109416, - "gzip": 27554 + "size": 109222, + "gzip": 27519 }, "react.production.min.js (NODE_PROD)": { "size": 12615, "gzip": 4659 }, "React-dev.js (FB_DEV)": { - "size": 110901, - "gzip": 28115 + "size": 110705, + "gzip": 28075 }, "React-prod.js (FB_PROD)": { "size": 56205, "gzip": 14329 }, "ReactDOMStack-dev.js (FB_DEV)": { - "size": 523568, - "gzip": 124900 + "size": 523202, + "gzip": 124830 }, "ReactDOMStack-prod.js (FB_PROD)": { "size": 351707, "gzip": 84367 }, "react-dom.development.js (NODE_DEV)": { - "size": 543299, - "gzip": 125435 + "size": 543145, + "gzip": 125402 }, "react-dom.production.min.js (NODE_PROD)": { "size": 116802, "gzip": 36707 }, "ReactDOMFiber-dev.js (FB_DEV)": { - "size": 797779, - "gzip": 184190 + "size": 797617, + "gzip": 184146 }, "ReactDOMFiber-prod.js (FB_PROD)": { "size": 407360, "gzip": 93460 }, "react-dom-server.development.js (NODE_DEV)": { - "size": 446778, - "gzip": 107862 + "size": 446422, + "gzip": 107796 }, "react-dom-server.production.min.js (NODE_PROD)": { "size": 101204, "gzip": 31227 }, "ReactDOMServerStack-dev.js (FB_DEV)": { - "size": 445529, - "gzip": 107719 + "size": 445173, + "gzip": 107652 }, "ReactDOMServerStack-prod.js (FB_PROD)": { "size": 332974, From d9fd08df265b51a64b829f4f857b18ebc671879b Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Apr 2017 17:03:22 +0100 Subject: [PATCH 03/43] Make ReactDebugCurrentFrame shared state between core and renderers (#9365) --- scripts/rollup/modules.js | 28 +++++++- scripts/rollup/results.json | 70 +++++++++---------- .../ReactDebugCurrentFrameRollupShim.js | 3 + src/fb/ReactFBEntry.js | 3 +- src/umd/ReactUMDEntry.js | 3 +- 5 files changed, 67 insertions(+), 40 deletions(-) create mode 100644 scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index 832e19b05c62e..03f897a1972e4 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -46,7 +46,9 @@ const fbjsModules = [ ]; const devOnlyFilesToStubOut = [ + "'ReactDebugCurrentFrame'", "'ReactComponentTreeHook'", + "'react/lib/ReactDebugCurrentFrame'", "'react/lib/ReactComponentTreeHook'", "'react-dom/lib/ReactPerf'", "'react-dom/lib/ReactTestUtils'", @@ -169,9 +171,6 @@ function getInternalModules() { // it doesn't pick them up and assumes they're external return { reactProdInvariant: resolve('./src/shared/utils/reactProdInvariant.js'), - 'react/lib/ReactDebugCurrentFrame': resolve( - './src/isomorphic/classic/element/ReactDebugCurrentFrame.js' - ), }; } @@ -277,6 +276,28 @@ function getReactComponentTreeHookModuleAlias(bundleType, isRenderer) { } } +// this works almost identically to the ReactCurrentOwner shim above +const shimReactDebugCurrentFrame = resolve( + './scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js' +); +const realReactDebugCurrentFrame = resolve( + './src/isomorphic/classic/element/ReactDebugCurrentFrame.js' +); + +function getReactDebugCurrentFrameModuleAlias(bundleType, isRenderer) { + if (isRenderer) { + return { + ReactDebugCurrentFrame: shimReactDebugCurrentFrame, + 'react/lib/ReactDebugCurrentFrame': shimReactDebugCurrentFrame, + }; + } else { + return { + ReactDebugCurrentFrame: realReactDebugCurrentFrame, + 'react/lib/ReactDebugCurrentFrame': realReactDebugCurrentFrame, + }; + } +} + const devOnlyModuleStub = `'${resolve('./scripts/rollup/shims/rollup/DevOnlyStubShim.js')}'`; function replaceDevOnlyStubbedModules(bundleType) { @@ -302,6 +323,7 @@ function getAliases(paths, bundleType, isRenderer, extractErrors) { return Object.assign( getReactCurrentOwnerModuleAlias(bundleType, isRenderer), getReactComponentTreeHookModuleAlias(bundleType, isRenderer), + getReactDebugCurrentFrameModuleAlias(bundleType, isRenderer), createModuleMap( paths, extractErrors && extractErrorCodes(errorCodeOpts), diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index 18e29d0eae1f4..ee47159e811e9 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,41 +1,41 @@ { - "branch": "master", + "branch": "debug-frame", "bundleSizes": { "react.development.js (UMD_DEV)": { - "size": 116208, - "gzip": 29564 + "size": 116245, + "gzip": 29572 }, "react.production.min.js (UMD_PROD)": { "size": 13719, "gzip": 5080 }, "react-dom.development.js (UMD_DEV)": { - "size": 564771, - "gzip": 130439 + "size": 563524, + "gzip": 130148 }, "react-dom.production.min.js (UMD_PROD)": { "size": 120123, "gzip": 37844 }, "react-dom-server.development.js (UMD_DEV)": { - "size": 477021, - "gzip": 115494 + "size": 475780, + "gzip": 115177 }, "react-dom-server.production.min.js (UMD_PROD)": { "size": 106349, "gzip": 32998 }, "react-art.development.js (UMD_DEV)": { - "size": 341151, - "gzip": 76261 + "size": 339599, + "gzip": 75952 }, "react-art.production.min.js (UMD_PROD)": { "size": 94939, "gzip": 28976 }, "react.development.js (NODE_DEV)": { - "size": 109222, - "gzip": 27519 + "size": 109259, + "gzip": 27527 }, "react.production.min.js (NODE_PROD)": { "size": 12615, @@ -50,64 +50,64 @@ "gzip": 14329 }, "ReactDOMStack-dev.js (FB_DEV)": { - "size": 523202, - "gzip": 124830 + "size": 521957, + "gzip": 124586 }, "ReactDOMStack-prod.js (FB_PROD)": { "size": 351707, "gzip": 84367 }, "react-dom.development.js (NODE_DEV)": { - "size": 543145, - "gzip": 125402 + "size": 541898, + "gzip": 125114 }, "react-dom.production.min.js (NODE_PROD)": { "size": 116802, "gzip": 36707 }, "ReactDOMFiber-dev.js (FB_DEV)": { - "size": 797617, - "gzip": 184146 + "size": 796380, + "gzip": 183920 }, "ReactDOMFiber-prod.js (FB_PROD)": { "size": 407360, "gzip": 93460 }, "react-dom-server.development.js (NODE_DEV)": { - "size": 446422, - "gzip": 107796 + "size": 445181, + "gzip": 107467 }, "react-dom-server.production.min.js (NODE_PROD)": { "size": 101204, "gzip": 31227 }, "ReactDOMServerStack-dev.js (FB_DEV)": { - "size": 445173, - "gzip": 107652 + "size": 443932, + "gzip": 107406 }, "ReactDOMServerStack-prod.js (FB_PROD)": { "size": 332974, "gzip": 80219 }, "ReactARTStack-dev.js (FB_DEV)": { - "size": 494340, - "gzip": 118840 + "size": 492711, + "gzip": 118489 }, "ReactARTStack-prod.js (FB_PROD)": { "size": 365115, "gzip": 87595 }, "react-art.development.js (NODE_DEV)": { - "size": 266386, - "gzip": 57183 + "size": 264816, + "gzip": 56881 }, "react-art.production.min.js (NODE_PROD)": { "size": 56517, "gzip": 17109 }, "ReactARTFiber-dev.js (FB_DEV)": { - "size": 265561, - "gzip": 57011 + "size": 263991, + "gzip": 56709 }, "ReactARTFiber-prod.js (FB_PROD)": { "size": 205194, @@ -122,20 +122,20 @@ "gzip": 84001 }, "ReactTestRendererFiber-dev.js (FB_DEV)": { - "size": 263452, - "gzip": 55974 + "size": 261900, + "gzip": 55671 }, "ReactTestRendererStack-dev.js (FB_DEV)": { - "size": 155222, - "gzip": 35662 + "size": 151142, + "gzip": 34709 }, "react-noop-renderer.development.js (NODE_DEV)": { - "size": 255447, - "gzip": 53933 + "size": 253895, + "gzip": 53629 }, "react-test-renderer.development.js (NODE_DEV)": { - "size": 264286, - "gzip": 56152 + "size": 262734, + "gzip": 55847 } } } \ No newline at end of file diff --git a/scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js b/scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js new file mode 100644 index 0000000000000..2174fb0166844 --- /dev/null +++ b/scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js @@ -0,0 +1,3 @@ +var ReactInternals = require('react').__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +module.exports = ReactInternals.ReactDebugCurrentFrame; diff --git a/src/fb/ReactFBEntry.js b/src/fb/ReactFBEntry.js index 74add5c91bc8b..e4d70b5d5994a 100644 --- a/src/fb/ReactFBEntry.js +++ b/src/fb/ReactFBEntry.js @@ -27,8 +27,9 @@ if (__DEV__) { Object.assign( ReactFBEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { - // ReactComponentTreeHook should not be included in production. + // These should not be included in production. ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'), + ReactDebugCurrentFrame: require('react/lib/ReactDebugCurrentFrame'), }, ); } diff --git a/src/umd/ReactUMDEntry.js b/src/umd/ReactUMDEntry.js index fd08211201659..1ab1076c8069b 100644 --- a/src/umd/ReactUMDEntry.js +++ b/src/umd/ReactUMDEntry.js @@ -27,8 +27,9 @@ if (__DEV__) { Object.assign( ReactUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { - // ReactComponentTreeHook should not be included in production. + // These should not be included in production. ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'), + ReactDebugCurrentFrame: require('react/lib/ReactDebugCurrentFrame'), }, ); } From d88696941d27dde3fec4d87b8e9d9ef3eaad6c5e Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Apr 2017 18:43:19 +0100 Subject: [PATCH 04/43] 16.0.0-alpha.8 --- package.json | 2 +- packages/react-art/package.json | 4 ++-- packages/react-dom/package.json | 4 ++-- packages/react-noop-renderer/package.json | 2 +- packages/react-test-renderer/package.json | 4 ++-- packages/react/package.json | 2 +- scripts/rollup/results.json | 16 ++++++++-------- src/ReactVersion.js | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 9cc3af3f92680..80b6c1d734d89 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-build", "private": true, - "version": "16.0.0-alpha.7", + "version": "16.0.0-alpha.8", "devDependencies": { "aliasify": "^2.0.0", "art": "^0.10.1", diff --git a/packages/react-art/package.json b/packages/react-art/package.json index b550b1e0fba68..8f9ddca085cd5 100644 --- a/packages/react-art/package.json +++ b/packages/react-art/package.json @@ -1,6 +1,6 @@ { "name": "react-art", - "version": "16.0.0-alpha.7", + "version": "16.0.0-alpha.8", "description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).", "main": "index.js", "repository": "facebook/react", @@ -23,7 +23,7 @@ "object-assign": "^4.1.0" }, "peerDependencies": { - "react": "^16.0.0-alpha.7" + "react": "^16.0.0-alpha.8" }, "files": [ "LICENSE", diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json index 831a2bed68e5e..a4a7f48e9a93e 100644 --- a/packages/react-dom/package.json +++ b/packages/react-dom/package.json @@ -1,6 +1,6 @@ { "name": "react-dom", - "version": "16.0.0-alpha.7", + "version": "16.0.0-alpha.8", "description": "React package for working with the DOM.", "main": "index.js", "repository": "facebook/react", @@ -18,7 +18,7 @@ "object-assign": "^4.1.0" }, "peerDependencies": { - "react": "^16.0.0-alpha.7" + "react": "^16.0.0-alpha.8" }, "files": [ "LICENSE", diff --git a/packages/react-noop-renderer/package.json b/packages/react-noop-renderer/package.json index 0402ad8d006dd..dd0906e193462 100644 --- a/packages/react-noop-renderer/package.json +++ b/packages/react-noop-renderer/package.json @@ -1,6 +1,6 @@ { "name": "react-noop-renderer", - "version": "16.0.0-alpha.7", + "version": "16.0.0-alpha.8", "private": true, "description": "React package for testing the Fiber reconciler.", "main": "index.js", diff --git a/packages/react-test-renderer/package.json b/packages/react-test-renderer/package.json index eb2b8732f3e4c..ef15cc2e25361 100644 --- a/packages/react-test-renderer/package.json +++ b/packages/react-test-renderer/package.json @@ -1,6 +1,6 @@ { "name": "react-test-renderer", - "version": "16.0.0-alpha.7", + "version": "16.0.0-alpha.8", "description": "React package for snapshot testing.", "main": "index.js", "repository": "facebook/react", @@ -19,7 +19,7 @@ "object-assign": "^4.1.0" }, "peerDependencies": { - "react": "^16.0.0-alpha.7" + "react": "^16.0.0-alpha.8" }, "files": [ "LICENSE", diff --git a/packages/react/package.json b/packages/react/package.json index 4ce3cc5b9ade9..1fc717340ef0f 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,7 +1,7 @@ { "name": "react", "description": "React is a JavaScript library for building user interfaces.", - "version": "16.0.0-alpha.7", + "version": "16.0.0-alpha.8", "keywords": [ "react" ], diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index ee47159e811e9..ea610c1fd6d44 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,5 +1,5 @@ { - "branch": "debug-frame", + "branch": "master", "bundleSizes": { "react.development.js (UMD_DEV)": { "size": 116245, @@ -23,7 +23,7 @@ }, "react-dom-server.production.min.js (UMD_PROD)": { "size": 106349, - "gzip": 32998 + "gzip": 32997 }, "react-art.development.js (UMD_DEV)": { "size": 339599, @@ -31,7 +31,7 @@ }, "react-art.production.min.js (UMD_PROD)": { "size": 94939, - "gzip": 28976 + "gzip": 28977 }, "react.development.js (NODE_DEV)": { "size": 109259, @@ -42,8 +42,8 @@ "gzip": 4659 }, "React-dev.js (FB_DEV)": { - "size": 110705, - "gzip": 28075 + "size": 110742, + "gzip": 28082 }, "React-prod.js (FB_PROD)": { "size": 56205, @@ -55,7 +55,7 @@ }, "ReactDOMStack-prod.js (FB_PROD)": { "size": 351707, - "gzip": 84367 + "gzip": 84366 }, "react-dom.development.js (NODE_DEV)": { "size": 541898, @@ -87,7 +87,7 @@ }, "ReactDOMServerStack-prod.js (FB_PROD)": { "size": 332974, - "gzip": 80219 + "gzip": 80217 }, "ReactARTStack-dev.js (FB_DEV)": { "size": 492711, @@ -95,7 +95,7 @@ }, "ReactARTStack-prod.js (FB_PROD)": { "size": 365115, - "gzip": 87595 + "gzip": 87596 }, "react-art.development.js (NODE_DEV)": { "size": 264816, diff --git a/src/ReactVersion.js b/src/ReactVersion.js index 9df23ee824959..d6ec94ed53dee 100644 --- a/src/ReactVersion.js +++ b/src/ReactVersion.js @@ -11,4 +11,4 @@ 'use strict'; -module.exports = '16.0.0-alpha.7'; +module.exports = '16.0.0-alpha.8'; From 6eaa539ad5fc608473540496b0f3b9c1688afeb0 Mon Sep 17 00:00:00 2001 From: Flarnie Marchan Date: Fri, 7 Apr 2017 13:47:54 -0700 Subject: [PATCH 05/43] Update example snippet in old 'React.addons' doc page (#9363) * Update example snippet in old 'React.addons' doc page This makes the example more consistent. * Add back the pointers in docs that were mistakenly removed In https://github.com/facebook/react/pull/9359 we accidentally removed pointers in some doc pages. Putting them back now. * Link to npm package instead of github page This seems like a more stable place to link to in the 'context' document. Based on @bvaughn's feedback in https://github.com/facebook/react/pull/9359 --- docs/docs/addons.md | 4 ++-- docs/docs/components-and-props.md | 2 ++ docs/docs/composition-vs-inheritance.md | 2 ++ docs/docs/conditional-rendering.md | 2 ++ docs/docs/context.md | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/docs/addons.md b/docs/docs/addons.md index 982f5e481fc59..d0f6a770b8ec4 100644 --- a/docs/docs/addons.md +++ b/docs/docs/addons.md @@ -34,8 +34,8 @@ The add-ons below are considered legacy and their use is discouraged. You can install the add-ons individually from npm (e.g. `npm install react-addons-create-fragment`) and import them: ```javascript -import Perf from 'react-addons-perf'; // ES6 -var Perf = require('react-addons-perf'); // ES5 with npm +import createFragment from 'react-addons-create-fragment'; // ES6 +var createFragment = require('react-addons-create-fragment'); // ES5 with npm ``` When using a CDN, you can use `react-with-addons.js` instead of `react.js`: diff --git a/docs/docs/components-and-props.md b/docs/docs/components-and-props.md index d1bf5ca9d3664..150138fb91b60 100644 --- a/docs/docs/components-and-props.md +++ b/docs/docs/components-and-props.md @@ -12,6 +12,8 @@ redirect_from: - "docs/transferring-props-zh-CN.html" - "tips/props-in-getInitialState-as-anti-pattern.html" - "tips/communicate-between-components.html" +prev: rendering-elements.html +next: state-and-lifecycle.html --- Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. diff --git a/docs/docs/composition-vs-inheritance.md b/docs/docs/composition-vs-inheritance.md index 2817811a669c4..0ac5cd45b21cc 100644 --- a/docs/docs/composition-vs-inheritance.md +++ b/docs/docs/composition-vs-inheritance.md @@ -3,6 +3,8 @@ id: composition-vs-inheritance title: Composition vs Inheritance permalink: docs/composition-vs-inheritance.html redirect_from: "docs/multiple-components.html" +prev: lifting-state-up.html +next: thinking-in-react.html --- React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components. diff --git a/docs/docs/conditional-rendering.md b/docs/docs/conditional-rendering.md index 7cfc60a8f9531..ea1be02a4c850 100644 --- a/docs/docs/conditional-rendering.md +++ b/docs/docs/conditional-rendering.md @@ -2,6 +2,8 @@ id: conditional-rendering title: Conditional Rendering permalink: docs/conditional-rendering.html +prev: handling-events.html +next: lists-and-keys.html redirect_from: "tips/false-in-jsx.html" --- diff --git a/docs/docs/context.md b/docs/docs/context.md index e3efaf5d5b308..718e941a06418 100644 --- a/docs/docs/context.md +++ b/docs/docs/context.md @@ -5,7 +5,7 @@ permalink: docs/context.html --- >Note: -> As of React v15.5 the `React.PropTypes` helper is deprecated, and we recommend using the [`prop-types` library](https://github.com/aackerman/PropTypes) to define `contextTypes`. +> As of React v15.5 the `React.PropTypes` helper is deprecated, and we recommend using the [`prop-types` library](https://www.npmjs.com/package/prop-types) to define `contextTypes`. With React, it's easy to track the flow of data through your React components. When you look at a component, you can see which props are being passed, which makes your apps easy to reason about. From 72196da82915bee400edb1599d4223926aa2a8a0 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Apr 2017 22:07:10 +0100 Subject: [PATCH 06/43] Replace shims with explicit React access from the renderers for shared global state (#9366) * Remove non-existent /lib/ from souce files * Replace all shims with explicit access This deletes shims and changes to access require('react').__DO_NOT_USE__ from renderers for global shared state. I cloned flattenChildren() and traverseAllChildren() because they relied on CurrentOwner but were used both from Stack and Isomorphic. The stack implementations will die, and the isomorphic ones can be changed to be optimized for Children specifically in the future. I also deleted UMD shims because they are now unnecessary. I moved the internals assignment to main modules since they're now used in tests, and made them direct UMD entry points. --- scripts/rollup/bundles.js | 19 +- scripts/rollup/modules.js | 101 +-------- scripts/rollup/results.json | 106 ++++----- .../rollup/ReactCheckPropTypesRollupShim.js | 3 - .../ReactComponentTreeHookRollupShim.js | 3 - .../rollup/ReactCurrentOwnerRollupShim.js | 3 - src/fb/ReactDOMFBEntry.js | 11 +- src/fb/ReactDOMFiberFBEntry.js | 66 +++--- src/fb/ReactFBEntry.js | 31 +-- src/isomorphic/React.js | 12 ++ .../children}/flattenChildren.js | 4 +- .../children}/traverseAllChildren.js | 2 +- .../__tests__/ReactComponentTreeHook-test.js | 4 +- .../ReactComponentTreeHook-test.native.js | 2 +- .../__tests__/ReactCompositeComponent-test.js | 2 +- .../ReactHostOperationHistoryHook-test.js | 2 +- src/renderers/__tests__/ReactPerf-test.js | 2 +- src/renderers/__tests__/refs-test.js | 4 +- src/renderers/dom/ReactDOM.js | 5 + src/renderers/dom/fiber/ReactDOMFiber.js | 5 + src/renderers/dom/shared/findDOMNode.js | 2 +- .../shared/hooks/ReactDOMInvalidARIAHook.js | 3 +- .../hooks/ReactDOMNullInputValuePropHook.js | 5 +- .../hooks/ReactDOMUnknownPropertyHook.js | 2 +- src/renderers/dom/stack/client/ReactMount.js | 2 +- src/renderers/native/findNodeHandle.js | 2 +- src/renderers/shared/ReactDebugTool.js | 2 +- .../shared/ReactGlobalSharedState.js | 27 +++ src/renderers/shared/fiber/ReactChildFiber.js | 2 +- .../shared/fiber/ReactFiberBeginWork.js | 2 +- .../shared/fiber/ReactFiberContext.js | 2 +- .../shared/fiber/ReactFiberScheduler.js | 2 +- .../shared/fiber/ReactFiberTreeReflection.js | 2 +- .../stack/reconciler/ReactChildReconciler.js | 10 +- .../reconciler/ReactCompositeComponent.js | 4 +- .../stack/reconciler/ReactMultiChild.js | 11 +- .../shared/stack/reconciler/ReactRef.js | 2 +- .../stack/reconciler/ReactUpdateQueue.js | 2 +- .../stack/reconciler/flattenStackChildren.js | 103 +++++++++ .../stack/reconciler/traverseStackChildren.js | 201 ++++++++++++++++++ src/test/ReactComponentTreeTestUtils.js | 2 +- src/test/ReactTestUtils.js | 2 +- src/umd/ReactDOMServerUMDEntry.js | 16 -- src/umd/ReactDOMUMDEntry.js | 23 -- src/umd/ReactUMDEntry.js | 37 ---- .../shims/ReactComponentTreeHookUMDShim.js | 18 -- src/umd/shims/ReactCurrentOwnerUMDShim.js | 18 -- src/umd/shims/ReactUMDShim.js | 16 -- 48 files changed, 509 insertions(+), 398 deletions(-) delete mode 100644 scripts/rollup/shims/rollup/ReactCheckPropTypesRollupShim.js delete mode 100644 scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js delete mode 100644 scripts/rollup/shims/rollup/ReactCurrentOwnerRollupShim.js rename src/{shared/utils => isomorphic/children}/flattenChildren.js (94%) rename src/{shared/utils => isomorphic/children}/traverseAllChildren.js (98%) create mode 100644 src/renderers/shared/ReactGlobalSharedState.js create mode 100644 src/renderers/shared/stack/reconciler/flattenStackChildren.js create mode 100644 src/renderers/shared/stack/reconciler/traverseStackChildren.js delete mode 100644 src/umd/ReactDOMServerUMDEntry.js delete mode 100644 src/umd/ReactDOMUMDEntry.js delete mode 100644 src/umd/ReactUMDEntry.js delete mode 100644 src/umd/shims/ReactComponentTreeHookUMDShim.js delete mode 100644 src/umd/shims/ReactCurrentOwnerUMDShim.js delete mode 100644 src/umd/shims/ReactUMDShim.js diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index a9010f0d0db35..fc221c5a5809c 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -44,7 +44,7 @@ const bundles = [ moduleName: 'React', sourceMap: false, }, - entry: 'src/umd/ReactUMDEntry.js', + entry: 'src/isomorphic/React.js', externals: [], fbEntry: 'src/fb/ReactFBEntry.js', hasteName: 'React', @@ -53,9 +53,6 @@ const bundles = [ manglePropertiesOnProd: false, name: 'react', paths: [ - 'src/umd/ReactUMDEntry.js', - 'src/umd/shims/**/*.js', - 'src/isomorphic/**/*.js', 'src/addons/**/*.js', @@ -76,7 +73,7 @@ const bundles = [ moduleName: 'ReactDOM', sourceMap: false, }, - entry: 'src/umd/ReactDOMUMDEntry.js', + entry: 'src/renderers/dom/ReactDOM.js', externals: [], fbEntry: 'src/fb/ReactDOMFBEntry.js', hasteName: 'ReactDOMStack', @@ -85,8 +82,6 @@ const bundles = [ manglePropertiesOnProd: false, name: 'react-dom-stack', paths: [ - 'src/umd/ReactDOMUMDEntry.js', - 'src/renderers/dom/**/*.js', 'src/renderers/shared/**/*.js', 'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM. @@ -106,7 +101,7 @@ const bundles = [ moduleName: 'ReactDOM', sourceMap: false, }, - entry: 'src/umd/ReactDOMUMDEntry.js', + entry: 'src/renderers/dom/fiber/ReactDOMFiber.js', externals: [], fbEntry: 'src/fb/ReactDOMFiberFBEntry.js', hasteName: 'ReactDOMFiber', @@ -115,8 +110,6 @@ const bundles = [ manglePropertiesOnProd: false, name: 'react-dom', paths: [ - 'src/umd/ReactDOMUMDEntry.js', - 'src/renderers/dom/**/*.js', 'src/renderers/shared/**/*.js', 'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM. @@ -139,17 +132,15 @@ const bundles = [ moduleName: 'ReactDOMServer', sourceMap: false, }, - entry: 'src/umd/ReactDOMServerUMDEntry.js', + entry: 'src/renderers/dom/ReactDOMServer.js', externals: [], - fbEntry: 'src/umd/ReactDOMServerUMDEntry.js', + fbEntry: 'src/renderers/dom/ReactDOMServer.js', hasteName: 'ReactDOMServerStack', isRenderer: true, label: 'dom-server', manglePropertiesOnProd: false, name: 'react-dom/server', paths: [ - 'src/umd/ReactDOMServerUMDEntry.js', - 'src/renderers/dom/**/*.js', 'src/renderers/shared/**/*.js', diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index 03f897a1972e4..e6b1904a468d0 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -48,10 +48,8 @@ const fbjsModules = [ const devOnlyFilesToStubOut = [ "'ReactDebugCurrentFrame'", "'ReactComponentTreeHook'", - "'react/lib/ReactDebugCurrentFrame'", - "'react/lib/ReactComponentTreeHook'", - "'react-dom/lib/ReactPerf'", - "'react-dom/lib/ReactTestUtils'", + "'ReactPerf'", + "'ReactTestUtils'", ]; // this function builds up a very niave Haste-like moduleMap @@ -114,7 +112,6 @@ function ignoreFBModules() { 'ReactDOMFeatureFlags', // In FB bundles, we preserve an inline require to ReactCurrentOwner. // See the explanation in FB version of ReactCurrentOwner in www: - 'react/lib/ReactCurrentOwner', 'ReactCurrentOwner', ]; } @@ -157,7 +154,7 @@ function getExternalModules(externals, bundleType, isRenderer) { case FB_DEV: case FB_PROD: fbjsModules.forEach(module => externalModules.push(module)); - externalModules.push('react/lib/ReactCurrentOwner', 'ReactCurrentOwner'); + externalModules.push('ReactCurrentOwner'); if (isRenderer) { externalModules.push('React'); } @@ -177,9 +174,6 @@ function getInternalModules() { function replaceInternalModules() { // we inline these modules in the bundles rather than leave them as external return { - "'react-dom/lib/ReactPerf'": `'${resolve('./src/renderers/shared/ReactPerf.js')}'`, - "'react-dom/lib/ReactTestUtils'": `'${resolve('./src/test/ReactTestUtils.js')}'`, - "'react-dom/lib/ReactInstanceMap'": `'${resolve('./src/renderers/shared/shared/ReactInstanceMap.js')}'`, "'react-dom'": `'${resolve('./src/renderers/dom/ReactDOM.js')}'`, }; } @@ -209,92 +203,16 @@ function getFbjsModuleAliases(bundleType) { function replaceFbjsModuleAliases(bundleType) { switch (bundleType) { - case UMD_DEV: - case UMD_PROD: - case NODE_DEV: - case NODE_PROD: - case RN_DEV: - case RN_PROD: - return {}; case FB_DEV: case FB_PROD: - // additionally we add mappings for "react" - // so they work correctly on FB, this will change soon + // Haste at FB doesn't currently allow case sensitive names, + // and product code already uses "React". In the future, + // we will either allow both variants or migrate to lowercase. return { "'react'": "'React'", }; - } -} - -// for renderers, we want them to require the __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner -// on the React bundle itself rather than require module directly. -// For the React bundle, ReactCurrentOwner should be bundled as part of the bundle -// itself and exposed on __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED -const shimReactCurrentOwner = resolve( - './scripts/rollup/shims/rollup/ReactCurrentOwnerRollupShim.js' -); -const realReactCurrentOwner = resolve( - './src/isomorphic/classic/element/ReactCurrentOwner.js' -); - -function getReactCurrentOwnerModuleAlias(bundleType, isRenderer) { - if (bundleType === FB_DEV || bundleType === FB_DEV) { - return {}; - } - if (isRenderer) { - return { - ReactCurrentOwner: shimReactCurrentOwner, - 'react/lib/ReactCurrentOwner': shimReactCurrentOwner, - }; - } else { - return { - ReactCurrentOwner: realReactCurrentOwner, - 'react/lib/ReactCurrentOwner': realReactCurrentOwner, - }; - } -} - -// this works almost identically to the ReactCurrentOwner shim above -const shimReactComponentTreeHook = resolve( - './scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js' -); -const realReactComponentTreeHook = resolve( - './src/isomorphic/hooks/ReactComponentTreeHook.js' -); - -function getReactComponentTreeHookModuleAlias(bundleType, isRenderer) { - if (isRenderer) { - return { - ReactComponentTreeHook: shimReactComponentTreeHook, - 'react/lib/ReactComponentTreeHook': shimReactComponentTreeHook, - }; - } else { - return { - ReactComponentTreeHook: realReactComponentTreeHook, - 'react/lib/ReactComponentTreeHook': realReactComponentTreeHook, - }; - } -} - -// this works almost identically to the ReactCurrentOwner shim above -const shimReactDebugCurrentFrame = resolve( - './scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js' -); -const realReactDebugCurrentFrame = resolve( - './src/isomorphic/classic/element/ReactDebugCurrentFrame.js' -); - -function getReactDebugCurrentFrameModuleAlias(bundleType, isRenderer) { - if (isRenderer) { - return { - ReactDebugCurrentFrame: shimReactDebugCurrentFrame, - 'react/lib/ReactDebugCurrentFrame': shimReactDebugCurrentFrame, - }; - } else { - return { - ReactDebugCurrentFrame: realReactDebugCurrentFrame, - 'react/lib/ReactDebugCurrentFrame': realReactDebugCurrentFrame, - }; + default: + return {}; } } @@ -321,9 +239,6 @@ function replaceDevOnlyStubbedModules(bundleType) { function getAliases(paths, bundleType, isRenderer, extractErrors) { return Object.assign( - getReactCurrentOwnerModuleAlias(bundleType, isRenderer), - getReactComponentTreeHookModuleAlias(bundleType, isRenderer), - getReactDebugCurrentFrameModuleAlias(bundleType, isRenderer), createModuleMap( paths, extractErrors && extractErrorCodes(errorCodeOpts), diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index ea610c1fd6d44..9d4a85e8cc540 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,29 +1,29 @@ { - "branch": "master", + "branch": "remove-lib-in-source", "bundleSizes": { "react.development.js (UMD_DEV)": { - "size": 116245, - "gzip": 29572 + "size": 116098, + "gzip": 29520 }, "react.production.min.js (UMD_PROD)": { - "size": 13719, - "gzip": 5080 + "size": 13707, + "gzip": 5073 }, "react-dom.development.js (UMD_DEV)": { - "size": 563524, - "gzip": 130148 + "size": 563844, + "gzip": 130190 }, "react-dom.production.min.js (UMD_PROD)": { - "size": 120123, - "gzip": 37844 + "size": 120191, + "gzip": 37860 }, "react-dom-server.development.js (UMD_DEV)": { - "size": 475780, - "gzip": 115177 + "size": 476049, + "gzip": 115267 }, "react-dom-server.production.min.js (UMD_PROD)": { - "size": 106349, - "gzip": 32997 + "size": 106489, + "gzip": 33035 }, "react-art.development.js (UMD_DEV)": { "size": 339599, @@ -34,68 +34,68 @@ "gzip": 28977 }, "react.development.js (NODE_DEV)": { - "size": 109259, - "gzip": 27527 + "size": 109110, + "gzip": 27479 }, "react.production.min.js (NODE_PROD)": { - "size": 12615, - "gzip": 4659 + "size": 12598, + "gzip": 4649 }, "React-dev.js (FB_DEV)": { - "size": 110742, - "gzip": 28082 + "size": 110875, + "gzip": 28140 }, "React-prod.js (FB_PROD)": { - "size": 56205, - "gzip": 14329 + "size": 56406, + "gzip": 14416 }, "ReactDOMStack-dev.js (FB_DEV)": { - "size": 521957, - "gzip": 124586 + "size": 522626, + "gzip": 124708 }, "ReactDOMStack-prod.js (FB_PROD)": { - "size": 351707, - "gzip": 84366 + "size": 352708, + "gzip": 84660 }, "react-dom.development.js (NODE_DEV)": { - "size": 541898, - "gzip": 125114 + "size": 542218, + "gzip": 125162 }, "react-dom.production.min.js (NODE_PROD)": { - "size": 116802, - "gzip": 36707 + "size": 116858, + "gzip": 36717 }, "ReactDOMFiber-dev.js (FB_DEV)": { - "size": 796380, - "gzip": 183920 + "size": 797268, + "gzip": 184134 }, "ReactDOMFiber-prod.js (FB_PROD)": { - "size": 407360, - "gzip": 93460 + "size": 407540, + "gzip": 93567 }, "react-dom-server.development.js (NODE_DEV)": { - "size": 445181, - "gzip": 107467 + "size": 445452, + "gzip": 107574 }, "react-dom-server.production.min.js (NODE_PROD)": { - "size": 101204, - "gzip": 31227 + "size": 101344, + "gzip": 31273 }, "ReactDOMServerStack-dev.js (FB_DEV)": { - "size": 443932, - "gzip": 107406 + "size": 444144, + "gzip": 107423 }, "ReactDOMServerStack-prod.js (FB_PROD)": { - "size": 332974, - "gzip": 80217 + "size": 333744, + "gzip": 80424 }, "ReactARTStack-dev.js (FB_DEV)": { - "size": 492711, - "gzip": 118489 + "size": 492651, + "gzip": 118470 }, "ReactARTStack-prod.js (FB_PROD)": { - "size": 365115, - "gzip": 87596 + "size": 365055, + "gzip": 87582 }, "react-art.development.js (NODE_DEV)": { "size": 264816, @@ -106,12 +106,12 @@ "gzip": 17109 }, "ReactARTFiber-dev.js (FB_DEV)": { - "size": 263991, - "gzip": 56709 + "size": 263951, + "gzip": 56683 }, "ReactARTFiber-prod.js (FB_PROD)": { - "size": 205194, - "gzip": 43039 + "size": 205154, + "gzip": 43017 }, "ReactNativeStack.js (RN)": { "size": 233993, @@ -122,12 +122,12 @@ "gzip": 84001 }, "ReactTestRendererFiber-dev.js (FB_DEV)": { - "size": 261900, - "gzip": 55671 + "size": 261860, + "gzip": 55645 }, "ReactTestRendererStack-dev.js (FB_DEV)": { - "size": 151142, - "gzip": 34709 + "size": 151102, + "gzip": 34699 }, "react-noop-renderer.development.js (NODE_DEV)": { "size": 253895, diff --git a/scripts/rollup/shims/rollup/ReactCheckPropTypesRollupShim.js b/scripts/rollup/shims/rollup/ReactCheckPropTypesRollupShim.js deleted file mode 100644 index f8866b76e6f1d..0000000000000 --- a/scripts/rollup/shims/rollup/ReactCheckPropTypesRollupShim.js +++ /dev/null @@ -1,3 +0,0 @@ -var React = require('react'); - -module.exports = React.checkPropTypes; diff --git a/scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js b/scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js deleted file mode 100644 index bcdc4d8787409..0000000000000 --- a/scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js +++ /dev/null @@ -1,3 +0,0 @@ -var ReactInternals = require('react').__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -module.exports = ReactInternals.ReactComponentTreeHook; diff --git a/scripts/rollup/shims/rollup/ReactCurrentOwnerRollupShim.js b/scripts/rollup/shims/rollup/ReactCurrentOwnerRollupShim.js deleted file mode 100644 index 3e5579b86c5af..0000000000000 --- a/scripts/rollup/shims/rollup/ReactCurrentOwnerRollupShim.js +++ /dev/null @@ -1,3 +0,0 @@ -var ReactInternals = require('react').__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -module.exports = ReactInternals.ReactCurrentOwner; diff --git a/src/fb/ReactDOMFBEntry.js b/src/fb/ReactDOMFBEntry.js index 7545c5ce3feec..754febaf3637a 100644 --- a/src/fb/ReactDOMFBEntry.js +++ b/src/fb/ReactDOMFBEntry.js @@ -11,7 +11,7 @@ var ReactDOM = require('ReactDOM'); -ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { +Object.assign(ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { // These should be easy to copy into react_contrib and remove from here: adler32: require('adler32'), getVendorPrefixedEventName: require('getVendorPrefixedEventName'), @@ -29,25 +29,24 @@ ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { SyntheticKeyboardEvent: require('SyntheticKeyboardEvent'), SyntheticMouseEvent: require('SyntheticMouseEvent'), // These are real internal dependencies that are trickier to remove: - EventPluginHub: require('EventPluginHub'), ReactBrowserEventEmitter: require('ReactBrowserEventEmitter'), ReactErrorUtils: require('ReactErrorUtils'), ReactDOMComponentTree: require('ReactDOMComponentTree'), - ReactInstanceMap: require('react-dom/lib/ReactInstanceMap'), + ReactInstanceMap: require('ReactInstanceMap'), // This is used for ajaxify on www: DOMProperty: require('DOMProperty'), // These are dependencies of TapEventPlugin: EventPluginUtils: require('EventPluginUtils'), EventPropagators: require('EventPropagators'), SyntheticUIEvent: require('SyntheticUIEvent'), -}; +}); if (__DEV__) { Object.assign(ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { // ReactPerf and ReactTestUtils currently only work with the DOM renderer // so we expose them from here, but only in DEV mode. - ReactPerf: require('react-dom/lib/ReactPerf'), - ReactTestUtils: require('react-dom/lib/ReactTestUtils'), + ReactPerf: require('ReactPerf'), + ReactTestUtils: require('ReactTestUtils'), }); } diff --git a/src/fb/ReactDOMFiberFBEntry.js b/src/fb/ReactDOMFiberFBEntry.js index c019d38c00424..188b9c71248ca 100644 --- a/src/fb/ReactDOMFiberFBEntry.js +++ b/src/fb/ReactDOMFiberFBEntry.js @@ -11,37 +11,39 @@ var ReactDOMFiber = require('ReactDOMFiber'); -ReactDOMFiber.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { - // These should be easy to copy into react_contrib and remove from here: - adler32: require('adler32'), - getVendorPrefixedEventName: require('getVendorPrefixedEventName'), - getEventCharCode: require('getEventCharCode'), - getEventKey: require('getEventKey'), - getEventTarget: require('getEventTarget'), - isEventSupported: require('isEventSupported'), - setInnerHTML: require('setInnerHTML'), - setTextContent: require('setTextContent'), - PooledClass: require('PooledClass'), - ReactDOMSelection: require('ReactDOMSelection'), - ReactInputSelection: require('ReactInputSelection'), - // These are mostly used in incorrect Flow typings and are codemoddable: - SyntheticEvent: require('SyntheticEvent'), - SyntheticKeyboardEvent: require('SyntheticKeyboardEvent'), - SyntheticMouseEvent: require('SyntheticMouseEvent'), - // These are real internal dependencies that are trickier to remove: - EventPluginHub: require('EventPluginHub'), - ReactBrowserEventEmitter: require('ReactBrowserEventEmitter'), - ReactErrorUtils: require('ReactErrorUtils'), - ReactFiberErrorLogger: require('ReactFiberErrorLogger'), - ReactDOMComponentTree: require('ReactDOMComponentTree'), - ReactInstanceMap: require('react-dom/lib/ReactInstanceMap'), - // This is used for ajaxify on www: - DOMProperty: require('DOMProperty'), - // These are dependencies of TapEventPlugin: - EventPluginUtils: require('EventPluginUtils'), - EventPropagators: require('EventPropagators'), - SyntheticUIEvent: require('SyntheticUIEvent'), -}; +Object.assign( + ReactDOMFiber.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, + { + // These should be easy to copy into react_contrib and remove from here: + adler32: require('adler32'), + getVendorPrefixedEventName: require('getVendorPrefixedEventName'), + getEventCharCode: require('getEventCharCode'), + getEventKey: require('getEventKey'), + getEventTarget: require('getEventTarget'), + isEventSupported: require('isEventSupported'), + setInnerHTML: require('setInnerHTML'), + setTextContent: require('setTextContent'), + PooledClass: require('PooledClass'), + ReactDOMSelection: require('ReactDOMSelection'), + ReactInputSelection: require('ReactInputSelection'), + // These are mostly used in incorrect Flow typings and are codemoddable: + SyntheticEvent: require('SyntheticEvent'), + SyntheticKeyboardEvent: require('SyntheticKeyboardEvent'), + SyntheticMouseEvent: require('SyntheticMouseEvent'), + // These are real internal dependencies that are trickier to remove: + ReactBrowserEventEmitter: require('ReactBrowserEventEmitter'), + ReactErrorUtils: require('ReactErrorUtils'), + ReactFiberErrorLogger: require('ReactFiberErrorLogger'), + ReactDOMComponentTree: require('ReactDOMComponentTree'), + ReactInstanceMap: require('ReactInstanceMap'), + // This is used for ajaxify on www: + DOMProperty: require('DOMProperty'), + // These are dependencies of TapEventPlugin: + EventPluginUtils: require('EventPluginUtils'), + EventPropagators: require('EventPropagators'), + SyntheticUIEvent: require('SyntheticUIEvent'), + }, +); if (__DEV__) { Object.assign( @@ -49,7 +51,7 @@ if (__DEV__) { { // ReactPerf and ReactTestUtils currently only work with the DOM renderer // so we expose them from here, but only in DEV mode. - ReactTestUtils: require('react-dom/lib/ReactTestUtils'), + ReactTestUtils: require('ReactTestUtils'), }, ); } diff --git a/src/fb/ReactFBEntry.js b/src/fb/ReactFBEntry.js index e4d70b5d5994a..ac3fe41e622d9 100644 --- a/src/fb/ReactFBEntry.js +++ b/src/fb/ReactFBEntry.js @@ -11,27 +11,12 @@ var React = require('React'); -// `version` will be added here by the React module. -var ReactFBEntry = Object.assign( - { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - ReactChildren: require('ReactChildren'), - getComponentName: require('getComponentName'), - flattenChildren: require('flattenChildren'), - }, - }, - React, -); +// Add existing internal dependencies from www codebase. +// The goal is to get rid of these with time or turn them into public APIs. +Object.assign(React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { + ReactChildren: require('ReactChildren'), + getComponentName: require('getComponentName'), + flattenChildren: require('flattenChildren'), +}); -if (__DEV__) { - Object.assign( - ReactFBEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, - { - // These should not be included in production. - ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'), - ReactDebugCurrentFrame: require('react/lib/ReactDebugCurrentFrame'), - }, - ); -} - -module.exports = ReactFBEntry; +module.exports = React; diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index 4e03036be26e8..5e57605f1c0fc 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -84,6 +84,18 @@ var React = { DOM: ReactDOMFactories, version: ReactVersion, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + ReactCurrentOwner: require('ReactCurrentOwner'), + }, }; +if (__DEV__) { + Object.assign(React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { + // These should not be included in production. + ReactComponentTreeHook: require('ReactComponentTreeHook'), + ReactDebugCurrentFrame: require('ReactDebugCurrentFrame'), + }); +} + module.exports = React; diff --git a/src/shared/utils/flattenChildren.js b/src/isomorphic/children/flattenChildren.js similarity index 94% rename from src/shared/utils/flattenChildren.js rename to src/isomorphic/children/flattenChildren.js index 21a5da7140abb..c6caa802bea29 100644 --- a/src/shared/utils/flattenChildren.js +++ b/src/isomorphic/children/flattenChildren.js @@ -28,7 +28,7 @@ if ( // https://github.com/facebook/react/issues/7240 // Remove the inline requires when we don't need them anymore: // https://github.com/facebook/react/pull/7178 - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactComponentTreeHook'); } /** @@ -49,7 +49,7 @@ function flattenSingleChildIntoContext( const keyUnique = result[name] === undefined; if (__DEV__) { if (!ReactComponentTreeHook) { - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactComponentTreeHook'); } if (!keyUnique) { warning( diff --git a/src/shared/utils/traverseAllChildren.js b/src/isomorphic/children/traverseAllChildren.js similarity index 98% rename from src/shared/utils/traverseAllChildren.js rename to src/isomorphic/children/traverseAllChildren.js index dd8b49fb58006..a68d1816d68ab 100644 --- a/src/shared/utils/traverseAllChildren.js +++ b/src/isomorphic/children/traverseAllChildren.js @@ -11,8 +11,8 @@ 'use strict'; -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); +var ReactCurrentOwner = require('ReactCurrentOwner'); var getIteratorFn = require('getIteratorFn'); var invariant = require('fbjs/lib/invariant'); diff --git a/src/renderers/__tests__/ReactComponentTreeHook-test.js b/src/renderers/__tests__/ReactComponentTreeHook-test.js index 0decdcd72fa88..2182aabf38c95 100644 --- a/src/renderers/__tests__/ReactComponentTreeHook-test.js +++ b/src/renderers/__tests__/ReactComponentTreeHook-test.js @@ -29,7 +29,7 @@ describe('ReactComponentTreeHook', () => { ReactDOM = require('react-dom'); ReactDOMServer = require('react-dom/server'); ReactInstanceMap = require('ReactInstanceMap'); - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactComponentTreeHook'); ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils'); }); @@ -2123,7 +2123,7 @@ describe('ReactComponentTreeHook', () => { ReactDOM = require('react-dom'); ReactDOMServer = require('react-dom/server'); ReactInstanceMap = require('ReactInstanceMap'); - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactComponentTreeHook'); ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils'); }); diff --git a/src/renderers/__tests__/ReactComponentTreeHook-test.native.js b/src/renderers/__tests__/ReactComponentTreeHook-test.native.js index 2de9bff4eff77..dd7be7d7014ce 100644 --- a/src/renderers/__tests__/ReactComponentTreeHook-test.native.js +++ b/src/renderers/__tests__/ReactComponentTreeHook-test.native.js @@ -36,7 +36,7 @@ describeStack('ReactComponentTreeHook', () => { React = require('react'); ReactNative = require('ReactNative'); ReactInstanceMap = require('ReactInstanceMap'); - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactComponentTreeHook'); ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils'); View = require('View'); createReactNativeComponentClass = require('createReactNativeComponentClass'); diff --git a/src/renderers/__tests__/ReactCompositeComponent-test.js b/src/renderers/__tests__/ReactCompositeComponent-test.js index 7259ec57b2a6b..7a7be1a0d1926 100644 --- a/src/renderers/__tests__/ReactCompositeComponent-test.js +++ b/src/renderers/__tests__/ReactCompositeComponent-test.js @@ -30,7 +30,7 @@ describe('ReactCompositeComponent', () => { ReactDOM = require('react-dom'); ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); ReactDOMServer = require('react-dom/server'); - ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); + ReactCurrentOwner = require('ReactCurrentOwner'); ReactPropTypes = require('ReactPropTypes'); ReactTestUtils = require('ReactTestUtils'); shallowEqual = require('fbjs/lib/shallowEqual'); diff --git a/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js b/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js index b787fa13f575d..81fc2683eb0c8 100644 --- a/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js +++ b/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js @@ -27,7 +27,7 @@ describeStack('ReactHostOperationHistoryHook', () => { jest.resetModules(); React = require('react'); - ReactPerf = require('react-dom/lib/ReactPerf'); + ReactPerf = require('ReactPerf'); ReactDOM = require('react-dom'); ReactDOMComponentTree = require('ReactDOMComponentTree'); ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook'); diff --git a/src/renderers/__tests__/ReactPerf-test.js b/src/renderers/__tests__/ReactPerf-test.js index 7957266e6d70c..f01b3193d0fdb 100644 --- a/src/renderers/__tests__/ReactPerf-test.js +++ b/src/renderers/__tests__/ReactPerf-test.js @@ -41,7 +41,7 @@ describeStack('ReactPerf', () => { React = require('react'); ReactDOM = require('react-dom'); - ReactPerf = require('react-dom/lib/ReactPerf'); + ReactPerf = require('ReactPerf'); ReactTestUtils = require('ReactTestUtils'); emptyFunction = require('fbjs/lib/emptyFunction'); diff --git a/src/renderers/__tests__/refs-test.js b/src/renderers/__tests__/refs-test.js index 758fb51af04bf..202a101f1c8dc 100644 --- a/src/renderers/__tests__/refs-test.js +++ b/src/renderers/__tests__/refs-test.js @@ -317,7 +317,7 @@ describe('string refs between fiber and stack', () => { it('attaches, detaches from fiber component with stack layer', () => { spyOn(console, 'error'); - const ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); + const ReactCurrentOwner = require('ReactCurrentOwner'); const ReactDOM = require('react-dom'); const ReactDOMFiber = require('ReactDOMFiber'); const ReactInstanceMap = require('ReactInstanceMap'); @@ -364,7 +364,7 @@ describe('string refs between fiber and stack', () => { it('attaches, detaches from stack component with fiber layer', () => { spyOn(console, 'error'); - const ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); + const ReactCurrentOwner = require('ReactCurrentOwner'); const ReactDOM = require('react-dom'); const ReactDOMFiber = require('ReactDOMFiber'); const ReactInstanceMap = require('ReactInstanceMap'); diff --git a/src/renderers/dom/ReactDOM.js b/src/renderers/dom/ReactDOM.js index 23a189f0c5c43..f5f976ea7d4aa 100644 --- a/src/renderers/dom/ReactDOM.js +++ b/src/renderers/dom/ReactDOM.js @@ -38,6 +38,11 @@ var ReactDOM = { unstable_batchedUpdates: ReactGenericBatching.batchedUpdates, unstable_renderSubtreeIntoContainer: ReactMount.renderSubtreeIntoContainer, /* eslint-enable camelcase */ + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + // For TapEventPlugin which is popular in open source + EventPluginHub: require('EventPluginHub'), + }, }; // Inject the runtime into a devtools global hook regardless of browser. diff --git a/src/renderers/dom/fiber/ReactDOMFiber.js b/src/renderers/dom/fiber/ReactDOMFiber.js index be4d800a7dfaa..80598dfb69079 100644 --- a/src/renderers/dom/fiber/ReactDOMFiber.js +++ b/src/renderers/dom/fiber/ReactDOMFiber.js @@ -539,6 +539,11 @@ var ReactDOM = { unstable_batchedUpdates: ReactGenericBatching.batchedUpdates, unstable_deferredUpdates: DOMRenderer.deferredUpdates, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + // For TapEventPlugin which is popular in open source + EventPluginHub: require('EventPluginHub'), + }, }; if (typeof injectInternals === 'function') { diff --git a/src/renderers/dom/shared/findDOMNode.js b/src/renderers/dom/shared/findDOMNode.js index ea1ef8d0f423d..35aa38518dd29 100644 --- a/src/renderers/dom/shared/findDOMNode.js +++ b/src/renderers/dom/shared/findDOMNode.js @@ -10,8 +10,8 @@ * @flow */ -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactInstanceMap = require('ReactInstanceMap'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var getComponentName = require('getComponentName'); var invariant = require('fbjs/lib/invariant'); diff --git a/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js b/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js index fb89d76220a66..6ada3db767a02 100644 --- a/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js +++ b/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js @@ -20,9 +20,10 @@ var warnedProperties = {}; var rARIA = new RegExp('^(aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'); if (__DEV__) { + var {ReactComponentTreeHook} = require('ReactGlobalSharedState'); var { getStackAddendumByID, - } = require('react/lib/ReactComponentTreeHook'); + } = ReactComponentTreeHook; } function getStackAddendum(debugID) { diff --git a/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js b/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js index 92e2cf2c197d4..6b722b48641af 100644 --- a/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js +++ b/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js @@ -15,9 +15,8 @@ var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber'); var warning = require('fbjs/lib/warning'); if (__DEV__) { - var { - getStackAddendumByID, - } = require('react/lib/ReactComponentTreeHook'); + var {ReactComponentTreeHook} = require('ReactGlobalSharedState'); + var {getStackAddendumByID} = ReactComponentTreeHook; } var didWarnValueNull = false; diff --git a/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js b/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js index c603e4ca76865..86b28f92e24c0 100644 --- a/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js +++ b/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js @@ -13,8 +13,8 @@ var DOMProperty = require('DOMProperty'); var EventPluginRegistry = require('EventPluginRegistry'); -var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber'); +var {ReactComponentTreeHook} = require('ReactGlobalSharedState'); var warning = require('fbjs/lib/warning'); diff --git a/src/renderers/dom/stack/client/ReactMount.js b/src/renderers/dom/stack/client/ReactMount.js index 93c21c84a2d91..9cbc2c91e44ed 100644 --- a/src/renderers/dom/stack/client/ReactMount.js +++ b/src/renderers/dom/stack/client/ReactMount.js @@ -14,7 +14,6 @@ var DOMLazyTree = require('DOMLazyTree'); var DOMProperty = require('DOMProperty'); var React = require('react'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactDOMContainerInfo = require('ReactDOMContainerInfo'); var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); @@ -25,6 +24,7 @@ var ReactMarkupChecksum = require('ReactMarkupChecksum'); var ReactReconciler = require('ReactReconciler'); var ReactUpdateQueue = require('ReactUpdateQueue'); var ReactUpdates = require('ReactUpdates'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var getContextForSubtree = require('getContextForSubtree'); var instantiateReactComponent = require('instantiateReactComponent'); diff --git a/src/renderers/native/findNodeHandle.js b/src/renderers/native/findNodeHandle.js index 68ec7e503da84..10008836ff70c 100644 --- a/src/renderers/native/findNodeHandle.js +++ b/src/renderers/native/findNodeHandle.js @@ -12,8 +12,8 @@ 'use strict'; -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactInstanceMap = require('ReactInstanceMap'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var invariant = require('fbjs/lib/invariant'); var warning = require('fbjs/lib/warning'); diff --git a/src/renderers/shared/ReactDebugTool.js b/src/renderers/shared/ReactDebugTool.js index b5ad9efeb9e1b..7be3d38fe73fb 100644 --- a/src/renderers/shared/ReactDebugTool.js +++ b/src/renderers/shared/ReactDebugTool.js @@ -14,8 +14,8 @@ var ReactInvalidSetStateWarningHook = require('ReactInvalidSetStateWarningHook'); var ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook'); -var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); +var {ReactComponentTreeHook} = require('ReactGlobalSharedState'); var performanceNow = require('fbjs/lib/performanceNow'); var warning = require('fbjs/lib/warning'); diff --git a/src/renderers/shared/ReactGlobalSharedState.js b/src/renderers/shared/ReactGlobalSharedState.js new file mode 100644 index 0000000000000..b9107b435857e --- /dev/null +++ b/src/renderers/shared/ReactGlobalSharedState.js @@ -0,0 +1,27 @@ +/** + * 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 ReactGlobalSharedState + */ + +'use strict'; + +var ReactInternals = require('react').__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactGlobalSharedState = { + ReactCurrentOwner: ReactInternals.ReactCurrentOwner, +}; + +if (__DEV__) { + Object.assign(ReactGlobalSharedState, { + ReactComponentTreeHook: ReactInternals.ReactComponentTreeHook, + ReactDebugCurrentFrame: ReactInternals.ReactDebugCurrentFrame, + }); +} + +module.exports = ReactGlobalSharedState; diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js index f56c80e1b9e7b..ac6eab0138dfe 100644 --- a/src/renderers/shared/fiber/ReactChildFiber.js +++ b/src/renderers/shared/fiber/ReactChildFiber.js @@ -36,7 +36,7 @@ var emptyObject = require('fbjs/lib/emptyObject'); var getIteratorFn = require('getIteratorFn'); var invariant = require('fbjs/lib/invariant'); var ReactFeatureFlags = require('ReactFeatureFlags'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); if (__DEV__) { var {getCurrentFiberStackAddendum} = require('ReactDebugCurrentFiber'); diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js index ad58d044613f2..3787e98be02d9 100644 --- a/src/renderers/shared/fiber/ReactFiberBeginWork.js +++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js @@ -60,8 +60,8 @@ var { Err, Ref, } = require('ReactTypeOfSideEffect'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactFiberClassComponent = require('ReactFiberClassComponent'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var invariant = require('fbjs/lib/invariant'); if (__DEV__) { diff --git a/src/renderers/shared/fiber/ReactFiberContext.js b/src/renderers/shared/fiber/ReactFiberContext.js index 67f37d1776162..e60fdd850eb16 100644 --- a/src/renderers/shared/fiber/ReactFiberContext.js +++ b/src/renderers/shared/fiber/ReactFiberContext.js @@ -34,8 +34,8 @@ const { } = require('ReactFiberStack'); if (__DEV__) { - var ReactDebugCurrentFrame = require('react/lib/ReactDebugCurrentFrame'); var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber'); + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState'); var { startPhaseTimer, stopPhaseTimer, diff --git a/src/renderers/shared/fiber/ReactFiberScheduler.js b/src/renderers/shared/fiber/ReactFiberScheduler.js index 520b1c895435b..80ff10825e531 100644 --- a/src/renderers/shared/fiber/ReactFiberScheduler.js +++ b/src/renderers/shared/fiber/ReactFiberScheduler.js @@ -45,8 +45,8 @@ var ReactFiberBeginWork = require('ReactFiberBeginWork'); var ReactFiberCompleteWork = require('ReactFiberCompleteWork'); var ReactFiberCommitWork = require('ReactFiberCommitWork'); var ReactFiberHostContext = require('ReactFiberHostContext'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactFeatureFlags = require('ReactFeatureFlags'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var getComponentName = require('getComponentName'); var {cloneFiber} = require('ReactFiber'); diff --git a/src/renderers/shared/fiber/ReactFiberTreeReflection.js b/src/renderers/shared/fiber/ReactFiberTreeReflection.js index 1cd0dea6ed743..b527587c45ee9 100644 --- a/src/renderers/shared/fiber/ReactFiberTreeReflection.js +++ b/src/renderers/shared/fiber/ReactFiberTreeReflection.js @@ -15,7 +15,7 @@ import type {Fiber} from 'ReactFiber'; var ReactInstanceMap = require('ReactInstanceMap'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var getComponentName = require('getComponentName'); var invariant = require('fbjs/lib/invariant'); diff --git a/src/renderers/shared/stack/reconciler/ReactChildReconciler.js b/src/renderers/shared/stack/reconciler/ReactChildReconciler.js index 7c9a13bfd064a..b0eedb0af9544 100644 --- a/src/renderers/shared/stack/reconciler/ReactChildReconciler.js +++ b/src/renderers/shared/stack/reconciler/ReactChildReconciler.js @@ -17,7 +17,7 @@ var ReactReconciler = require('ReactReconciler'); var instantiateReactComponent = require('instantiateReactComponent'); var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); -var traverseAllChildren = require('traverseAllChildren'); +var traverseStackChildren = require('traverseStackChildren'); var warning = require('fbjs/lib/warning'); var ReactComponentTreeHook; @@ -32,7 +32,7 @@ if ( // https://github.com/facebook/react/issues/7240 // Remove the inline requires when we don't need them anymore: // https://github.com/facebook/react/pull/7178 - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook; } function instantiateChild(childInstances, child, name, selfDebugID) { @@ -40,7 +40,7 @@ function instantiateChild(childInstances, child, name, selfDebugID) { var keyUnique = childInstances[name] === undefined; if (__DEV__) { if (!ReactComponentTreeHook) { - ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook; } if (!keyUnique) { warning( @@ -84,14 +84,14 @@ var ReactChildReconciler = { var childInstances = {}; if (__DEV__) { - traverseAllChildren( + traverseStackChildren( nestedChildNodes, (childInsts, child, name) => instantiateChild(childInsts, child, name, selfDebugID), childInstances, ); } else { - traverseAllChildren(nestedChildNodes, instantiateChild, childInstances); + traverseStackChildren(nestedChildNodes, instantiateChild, childInstances); } return childInstances; }, diff --git a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js index d2217db557af9..6649dffaf64b5 100644 --- a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js @@ -14,16 +14,16 @@ var React = require('react'); var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactCompositeComponentTypes = require('ReactCompositeComponentTypes'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactErrorUtils = require('ReactErrorUtils'); var ReactFeatureFlags = require('ReactFeatureFlags'); var ReactInstanceMap = require('ReactInstanceMap'); var ReactInstrumentation = require('ReactInstrumentation'); var ReactNodeTypes = require('ReactNodeTypes'); var ReactReconciler = require('ReactReconciler'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); if (__DEV__) { - var ReactDebugCurrentFrame = require('react/lib/ReactDebugCurrentFrame'); + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState'); var warningAboutMissingGetChildContext = {}; } diff --git a/src/renderers/shared/stack/reconciler/ReactMultiChild.js b/src/renderers/shared/stack/reconciler/ReactMultiChild.js index 19fd366a38e61..8bde4e26ffffa 100644 --- a/src/renderers/shared/stack/reconciler/ReactMultiChild.js +++ b/src/renderers/shared/stack/reconciler/ReactMultiChild.js @@ -15,12 +15,12 @@ var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactInstanceMap = require('ReactInstanceMap'); var ReactInstrumentation = require('ReactInstrumentation'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactReconciler = require('ReactReconciler'); var ReactChildReconciler = require('ReactChildReconciler'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var emptyFunction = require('fbjs/lib/emptyFunction'); -var flattenChildren = require('flattenChildren'); +var flattenStackChildren = require('flattenStackChildren'); var invariant = require('fbjs/lib/invariant'); /** @@ -212,7 +212,7 @@ var ReactMultiChild = { if (this._currentElement) { try { ReactCurrentOwner.current = this._currentElement._owner; - nextChildren = flattenChildren( + nextChildren = flattenStackChildren( nextNestedChildrenElements, selfDebugID, ); @@ -233,7 +233,10 @@ var ReactMultiChild = { return nextChildren; } } - nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID); + nextChildren = flattenStackChildren( + nextNestedChildrenElements, + selfDebugID, + ); ReactChildReconciler.updateChildren( prevChildren, nextChildren, diff --git a/src/renderers/shared/stack/reconciler/ReactRef.js b/src/renderers/shared/stack/reconciler/ReactRef.js index cae62c717b26f..89abe98df736f 100644 --- a/src/renderers/shared/stack/reconciler/ReactRef.js +++ b/src/renderers/shared/stack/reconciler/ReactRef.js @@ -21,7 +21,7 @@ var ReactRef = {}; if (__DEV__) { var ReactCompositeComponentTypes = require('ReactCompositeComponentTypes'); - var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); + var {ReactComponentTreeHook} = require('ReactGlobalSharedState'); var warning = require('fbjs/lib/warning'); var warnedAboutStatelessRefs = {}; diff --git a/src/renderers/shared/stack/reconciler/ReactUpdateQueue.js b/src/renderers/shared/stack/reconciler/ReactUpdateQueue.js index 20cbb87fbbe40..e34cfee15b960 100644 --- a/src/renderers/shared/stack/reconciler/ReactUpdateQueue.js +++ b/src/renderers/shared/stack/reconciler/ReactUpdateQueue.js @@ -11,10 +11,10 @@ 'use strict'; -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactInstanceMap = require('ReactInstanceMap'); var ReactInstrumentation = require('ReactInstrumentation'); var ReactUpdates = require('ReactUpdates'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); if (__DEV__) { var warning = require('fbjs/lib/warning'); diff --git a/src/renderers/shared/stack/reconciler/flattenStackChildren.js b/src/renderers/shared/stack/reconciler/flattenStackChildren.js new file mode 100644 index 0000000000000..4abb79e78f054 --- /dev/null +++ b/src/renderers/shared/stack/reconciler/flattenStackChildren.js @@ -0,0 +1,103 @@ +/** + * 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 flattenStackChildren + * @flow + */ + +'use strict'; + +var KeyEscapeUtils = require('KeyEscapeUtils'); +var traverseStackChildren = require('traverseStackChildren'); +var warning = require('fbjs/lib/warning'); + +var ReactComponentTreeHook; + +if ( + typeof process !== 'undefined' && + process.env && + process.env.NODE_ENV === 'test' +) { + // Temporary hack. + // Inline requires don't work well with Jest: + // https://github.com/facebook/react/issues/7240 + // Remove the inline requires when we don't need them anymore: + // https://github.com/facebook/react/pull/7178 + ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook; +} + +/** + * @param {function} traverseContext Context passed through traversal. + * @param {?ReactComponent} child React child component. + * @param {!string} name String name of key path to child. + * @param {number=} selfDebugID Optional debugID of the current internal instance. + */ +function flattenSingleChildIntoContext( + traverseContext: mixed, + child: ReactElement, + name: string, + selfDebugID?: number, +): void { + // We found a component instance. + if (traverseContext && typeof traverseContext === 'object') { + const result = traverseContext; + const keyUnique = result[name] === undefined; + if (__DEV__) { + if (!ReactComponentTreeHook) { + ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook; + } + if (!keyUnique) { + warning( + false, + 'flattenChildren(...): Encountered two children with the same key, ' + + '`%s`. Child keys must be unique; when two children share a key, only ' + + 'the first child will be used.%s', + KeyEscapeUtils.unescape(name), + ReactComponentTreeHook.getStackAddendumByID(selfDebugID), + ); + } + } + if (keyUnique && child != null) { + result[name] = child; + } + } +} + +/** + * Flattens children that are typically specified as `props.children`. Any null + * children will not be included in the resulting object. + * @return {!object} flattened children keyed by name. + */ +function flattenStackChildren( + children: ReactElement, + selfDebugID?: number, +): ?{[name: string]: ReactElement} { + if (children == null) { + return children; + } + var result = {}; + + if (__DEV__) { + traverseStackChildren( + children, + (traverseContext, child, name) => + flattenSingleChildIntoContext( + traverseContext, + child, + name, + selfDebugID, + ), + result, + ); + } else { + traverseStackChildren(children, flattenSingleChildIntoContext, result); + } + return result; +} + +module.exports = flattenStackChildren; diff --git a/src/renderers/shared/stack/reconciler/traverseStackChildren.js b/src/renderers/shared/stack/reconciler/traverseStackChildren.js new file mode 100644 index 0000000000000..b717ea28fbc02 --- /dev/null +++ b/src/renderers/shared/stack/reconciler/traverseStackChildren.js @@ -0,0 +1,201 @@ +/** + * 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 traverseStackChildren + */ + +'use strict'; + +var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); +var {ReactCurrentOwner} = require('ReactGlobalSharedState'); + +var getIteratorFn = require('getIteratorFn'); +var invariant = require('fbjs/lib/invariant'); +var KeyEscapeUtils = require('KeyEscapeUtils'); +var warning = require('fbjs/lib/warning'); + +var SEPARATOR = '.'; +var SUBSEPARATOR = ':'; + +/** + * This is inlined from ReactElement since this file is shared between + * isomorphic and renderers. We could extract this to a + * + */ + +/** + * TODO: Test that a single child and an array with one item have the same key + * pattern. + */ + +var didWarnAboutMaps = false; + +/** + * Generate a key string that identifies a component within a set. + * + * @param {*} component A component that could contain a manual key. + * @param {number} index Index that is used if a manual key is not provided. + * @return {string} + */ +function getComponentKey(component, index) { + // Do some typechecking here since we call this blindly. We want to ensure + // that we don't block potential future ES APIs. + if (component && typeof component === 'object' && component.key != null) { + // Explicit key + return KeyEscapeUtils.escape(component.key); + } + // Implicit key determined by the index in the set + return index.toString(36); +} + +/** + * @param {?*} children Children tree container. + * @param {!string} nameSoFar Name of the key path so far. + * @param {!function} callback Callback to invoke with each child found. + * @param {?*} traverseContext Used to pass information throughout the traversal + * process. + * @return {!number} The number of children in this subtree. + */ +function traverseStackChildrenImpl( + children, + nameSoFar, + callback, + traverseContext, +) { + var type = typeof children; + + if (type === 'undefined' || type === 'boolean') { + // All of the above are perceived as null. + children = null; + } + + if ( + children === null || + type === 'string' || + type === 'number' || + // The following is inlined from ReactElement. This means we can optimize + // some checks. React Fiber also inlines this logic for similar purposes. + (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) + ) { + callback( + traverseContext, + children, + // If it's the only child, treat the name as if it was wrapped in an array + // so that it's consistent if the number of children grows. + nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, + ); + return 1; + } + + var child; + var nextName; + var subtreeCount = 0; // Count of children found in the current subtree. + var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; + + if (Array.isArray(children)) { + for (var i = 0; i < children.length; i++) { + child = children[i]; + nextName = nextNamePrefix + getComponentKey(child, i); + subtreeCount += traverseStackChildrenImpl( + child, + nextName, + callback, + traverseContext, + ); + } + } else { + var iteratorFn = getIteratorFn(children); + if (iteratorFn) { + if (__DEV__) { + // Warn about using Maps as children + if (iteratorFn === children.entries) { + let mapsAsChildrenAddendum = ''; + if (ReactCurrentOwner.current) { + var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName(); + if (mapsAsChildrenOwnerName) { + mapsAsChildrenAddendum = '\n\nCheck the render method of `' + + mapsAsChildrenOwnerName + + '`.'; + } + } + warning( + didWarnAboutMaps, + 'Using Maps as children is unsupported and will likely yield ' + + 'unexpected results. Convert it to a sequence/iterable of keyed ' + + 'ReactElements instead.%s', + mapsAsChildrenAddendum, + ); + didWarnAboutMaps = true; + } + } + + var iterator = iteratorFn.call(children); + var step; + var ii = 0; + while (!(step = iterator.next()).done) { + child = step.value; + nextName = nextNamePrefix + getComponentKey(child, ii++); + subtreeCount += traverseStackChildrenImpl( + child, + nextName, + callback, + traverseContext, + ); + } + } else if (type === 'object') { + var addendum = ''; + if (__DEV__) { + addendum = ' If you meant to render a collection of children, use an array ' + + 'instead.'; + if (ReactCurrentOwner.current) { + var name = ReactCurrentOwner.current.getName(); + if (name) { + addendum += '\n\nCheck the render method of `' + name + '`.'; + } + } + } + var childrenString = '' + children; + invariant( + false, + 'Objects are not valid as a React child (found: %s).%s', + childrenString === '[object Object]' + ? 'object with keys {' + Object.keys(children).join(', ') + '}' + : childrenString, + addendum, + ); + } + } + + return subtreeCount; +} + +/** + * Traverses children that are typically specified as `props.children`, but + * might also be specified through attributes: + * + * - `traverseStackChildren(this.props.children, ...)` + * - `traverseStackChildren(this.props.leftPanelChildren, ...)` + * + * The `traverseContext` is an optional argument that is passed through the + * entire traversal. It can be used to store accumulations or anything else that + * the callback might find relevant. + * + * @param {?*} children Children tree object. + * @param {!function} callback To invoke upon traversing each child. + * @param {?*} traverseContext Context for traversal. + * @return {!number} The number of children in this subtree. + */ +function traverseStackChildren(children, callback, traverseContext) { + if (children == null) { + return 0; + } + + return traverseStackChildrenImpl(children, '', callback, traverseContext); +} + +module.exports = traverseStackChildren; diff --git a/src/test/ReactComponentTreeTestUtils.js b/src/test/ReactComponentTreeTestUtils.js index 91f4e36b8a2e2..10dca25e19b6b 100644 --- a/src/test/ReactComponentTreeTestUtils.js +++ b/src/test/ReactComponentTreeTestUtils.js @@ -11,7 +11,7 @@ 'use strict'; -var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); +var ReactComponentTreeHook = require('ReactComponentTreeHook'); function getRootDisplayNames() { return ReactComponentTreeHook.getRootIDs().map( diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index d3190de877359..d0ca2fe4063e0 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -21,7 +21,7 @@ var ReactDOM = require('react-dom'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactFiberTreeReflection = require('ReactFiberTreeReflection'); -var ReactInstanceMap = require('react-dom/lib/ReactInstanceMap'); +var ReactInstanceMap = require('ReactInstanceMap'); var ReactTypeOfWork = require('ReactTypeOfWork'); var ReactGenericBatching = require('ReactGenericBatching'); var SyntheticEvent = require('SyntheticEvent'); diff --git a/src/umd/ReactDOMServerUMDEntry.js b/src/umd/ReactDOMServerUMDEntry.js deleted file mode 100644 index 7a55540e2b729..0000000000000 --- a/src/umd/ReactDOMServerUMDEntry.js +++ /dev/null @@ -1,16 +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. - * - * @providesModule ReactDOMServerUMDEntry - */ - -'use strict'; - -var ReactDOMServer = require('ReactDOMServer'); - -module.exports = ReactDOMServer; diff --git a/src/umd/ReactDOMUMDEntry.js b/src/umd/ReactDOMUMDEntry.js deleted file mode 100644 index 1749f30acc484..0000000000000 --- a/src/umd/ReactDOMUMDEntry.js +++ /dev/null @@ -1,23 +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. - * - * @providesModule ReactDOMUMDEntry - */ - -'use strict'; - -var ReactDOM = require('ReactDOMFiber'); - -var ReactDOMUMDEntry = Object.assign(ReactDOM, { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - // For TapEventPlugin which is popular in open source - EventPluginHub: require('EventPluginHub'), - }, -}); - -module.exports = ReactDOMUMDEntry; diff --git a/src/umd/ReactUMDEntry.js b/src/umd/ReactUMDEntry.js deleted file mode 100644 index 1ab1076c8069b..0000000000000 --- a/src/umd/ReactUMDEntry.js +++ /dev/null @@ -1,37 +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. - * - * @providesModule ReactUMDEntry - */ - -'use strict'; - -var React = require('React'); - -// `version` will be added here by the React module. -var ReactUMDEntry = Object.assign( - { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - ReactCurrentOwner: require('react/lib/ReactCurrentOwner'), - }, - }, - React, -); - -if (__DEV__) { - Object.assign( - ReactUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, - { - // These should not be included in production. - ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'), - ReactDebugCurrentFrame: require('react/lib/ReactDebugCurrentFrame'), - }, - ); -} - -module.exports = ReactUMDEntry; diff --git a/src/umd/shims/ReactComponentTreeHookUMDShim.js b/src/umd/shims/ReactComponentTreeHookUMDShim.js deleted file mode 100644 index 82a5cf6e15215..0000000000000 --- a/src/umd/shims/ReactComponentTreeHookUMDShim.js +++ /dev/null @@ -1,18 +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. - * - * @providesModule ReactComponentTreeHookUMDShim - */ - -/* globals React */ - -'use strict'; - -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -module.exports = ReactInternals.ReactComponentTreeHook; diff --git a/src/umd/shims/ReactCurrentOwnerUMDShim.js b/src/umd/shims/ReactCurrentOwnerUMDShim.js deleted file mode 100644 index 79ef232b54b07..0000000000000 --- a/src/umd/shims/ReactCurrentOwnerUMDShim.js +++ /dev/null @@ -1,18 +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. - * - * @providesModule ReactCurrentOwnerUMDShim - */ - -/* globals React */ - -'use strict'; - -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -module.exports = ReactInternals.ReactCurrentOwner; diff --git a/src/umd/shims/ReactUMDShim.js b/src/umd/shims/ReactUMDShim.js deleted file mode 100644 index 84ae35c47505b..0000000000000 --- a/src/umd/shims/ReactUMDShim.js +++ /dev/null @@ -1,16 +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. - * - * @providesModule ReactUMDShim - */ - -/* globals React */ - -'use strict'; - -module.exports = React; From e5ce3fd368fd3022a910550c8b5c9639997d613a Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Fri, 7 Apr 2017 14:41:16 -0700 Subject: [PATCH 07/43] Blog post and changelog for 15.5.0 (#9368) --- CHANGELOG.md | 28 +++ docs/_data/authors.yml | 3 + docs/_posts/2017-04-07-react-v15.5.0.md | 227 ++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 docs/_posts/2017-04-07-react-v15.5.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ce56e7e77896..3765106bc4ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,31 @@ +## 15.5.0 (April 7, 2017) + +### React + +* Added a deprecation warning for `React.createClass`. Points users to create-react-class instead. ([@acdlite](https://github.com/acdlite) in [d9a4fa4](https://github.com/facebook/react/commit/d9a4fa4f51c6da895e1655f32255cf72c0fe620e)) +* Added a deprecation warning for `React.PropTypes`. Points users to prop-types instead. ([@acdlite](https://github.com/acdlite) in [043845c](https://github.com/facebook/react/commit/043845ce75ea0812286bbbd9d34994bb7e01eb28)) +* Fixed an issue when using `ReactDOM` together with `ReactDOMServer`. ([@wacii](https://github.com/wacii) in [#9005](https://github.com/facebook/react/pull/9005)) +* Fixed issue with Closure Compiler. ([@anmonteiro](https://github.com/anmonteiro) in [#8895](https://github.com/facebook/react/pull/8895)) +* Another fix for Closure Compiler. ([@Shastel](https://github.com/Shastel) in [#8882](https://github.com/facebook/react/pull/8882)) +* Added component stack info to invalid element type warning. ([@n3tr](https://github.com/n3tr) in [#8495](https://github.com/facebook/react/pull/8495)) + +### React DOM + +* Fixed Chrome bug when backspacing in number inputs. ([@nhunzaker](https://github.com/nhunzaker) in [#7359](https://github.com/facebook/react/pull/7359)) +* Added `react-dom/test-utils`, which exports the React Test Utils. ([@bvaughn](https://github.com/bvaughn)) + +### React Test Renderer + +* Fixed bug where `componentWillUnmount` was not called for children. ([@gre](https://github.com/gre) in [#8512](https://github.com/facebook/react/pull/8512)) +* Added `react-test-renderer/shallow`, which exports the shallow renderer. ([@bvaughn](https://github.com/bvaughn)) + +### React Addons + +* Last release for addons; they will no longer be actively maintained. +* Removed `peerDependencies` so that addons continue to work indefinitely. ([@acdlite](https://github.com/acdlite) and [@bvaughn](https://github.com/bvaughn) in [8a06cd7](https://github.com/facebook/react/commit/8a06cd7a786822fce229197cac8125a551e8abfa) and [67a8db3](https://github.com/facebook/react/commit/67a8db3650d724a51e70be130e9008806402678a)) +* Updated to remove references to `React.createClass` and `React.PropTypes` ([@acdlite](https://github.com/acdlite) in [12a96b9](https://github.com/facebook/react/commit/12a96b94823d6b6de6b1ac13bd576864abd50175)) +* `react-addons-test-utils` is deprecated. Use `react-dom/test-utils` and `react-test-renderer/shallow` instead. ([@bvaughn](https://github.com/bvaughn)) + ## 15.4.2 (January 6, 2017) ### React diff --git a/docs/_data/authors.yml b/docs/_data/authors.yml index eff00b7e2eb59..d52ee1d96d528 100644 --- a/docs/_data/authors.yml +++ b/docs/_data/authors.yml @@ -1,6 +1,9 @@ # Map of short name to more information. `name` will be used but if you don't # want to use your real name, just use whatever. If url is included, your name # will be a link to the provided url. +acdlite: + name: Andrew Clark + url: https://twitter.com/acdlite benigeri: name: Paul Benigeri url: https://github.com/benigeri diff --git a/docs/_posts/2017-04-07-react-v15.5.0.md b/docs/_posts/2017-04-07-react-v15.5.0.md new file mode 100644 index 0000000000000..050c304442c4d --- /dev/null +++ b/docs/_posts/2017-04-07-react-v15.5.0.md @@ -0,0 +1,227 @@ +--- +title: "React v15.5.0" +author: acdlite +--- + +It's been exactly one year since the last breaking change to React. Our next major release, React 16, will include some exciting improvements, including a [complete rewrite](https://www.youtube.com/watch?v=ZCuYPiUIONs) of React's internals. [We take stability seriously](/react/contributing/design-principles.html#stability), and are committed to bringing those improvements to all of our users with minimal effort. + +To that end, today we're releasing React 15.5.0. + +### New Deprecation Warnings + +The biggest change is that we've extracted `React.PropTypes` and `React.createClass` into their own packages. Both are still accessible via the main `React` object, but using either will log a one-time deprecation warning to the console when in development mode. This will enable future code size optimizations. + +These warnings will not affect the behavior of your application. However, we realize they may cause some frustration, particularly if you use a testing framework that treats `console.error` as a failure. + +**Adding new warnings is not something we do lightly.** Warnings in React are not mere suggestions — they are integral to our strategy of keeping as many people as possible on the latest version of React. We never add warnings without providing an incremental path forward. + +So while the warnings may cause frustration in the short-term, we believe **prodding developers to migrate their codebases now prevents greater frustration in the future**. Proactively fixing warnings ensures you are prepared for the next major release. If your app produces zero warnings in 15.5, it should continue to work in 16 without any changes. + +For each of these new deprecations, we've provided a codemod to automatically migrate your code. They are available as part of the [react-codemod](https://github.com/reactjs/react-codemod) project. + +### Migrating from React.PropTypes + +Prop types are a feature for runtime validation of props during development. We've extracted the built-in prop types to a separate package to reflect the fact that not everybody uses them. + +In 15.5, instead of accessing `PropTypes` from the main `React` object, install the `prop-types` package and import them from there: + +```js{11,16,25} +// Before (15.4 and below) +import React from 'react'; + +class Component extends React.Component { + render() { + return
{this.props.text}
; + } +} + +Component.propTypes = { + text: React.PropTypes.string.isRequired, +} + +// After (15.5) +import React from 'react'; +import PropTypes from 'prop-types'; + +class Component extends React.Component { + render() { + return
{this.props.text}
; + } +} + +Component.propTypes = { + text: PropTypes.string.isRequired, +}; +``` + +The [codemod](https://github.com/reactjs/react-codemod#react-proptypes-to-prop-types) for this change performs this conversion automatically. Basic usage: + +```bash +jscodeshift -t react-codemod/transforms/React-PropTypes-to-prop-types.js +``` + + +The `propTypes`, `contextTypes`, and `childContextTypes` APIs will work exactly as before. The only change is that the built-in validators now live in a separate package. + +You may also consider using [Flow](https://flow.org/) to statically type check your JavaScript code, including [React components](https://flow.org/en/docs/frameworks/react/#setup-flow-with-react-a-classtoc-idtoc-setup-flow-with-react-hreftoc-setup-flow-with-reacta). + +### Migrating from React.createClass + +When React was initially released, there was no idiomatic way to create classes in JavaScript, so we provided our own: `React.createClass`. + +Later, classes were added to the language as part of ES2015, so we added the ability to create React components using JavaScript classes. **Along with functional components, JavaScript classes are now the [preferred way to create components in React](/react/docs/components-and-props.html#functional-and-class-components).** + +For your existing `createClass` components, we recommend that you migrate them to JavaScript classes. However, if you have components that rely on mixins, converting to classes may not be immediately feasible. If so, `create-react-class` is available on npm as a drop-in replacement: + +```js{4,13,15} +// Before (15.4 and below) +var React = require('react'); + +var Component = React.createClass({ + mixins: [MixinA], + render() { + return ; + } +}); + +// After (15.5) +var React = require('react'); +var createReactClass = require('create-react-class'); + +var Component = createReactClass({ + mixins: [MixinA], + render() { + return ; + } +}); +``` + +Your components will continue to work the same as they did before. + +The [codemod](https://github.com/reactjs/react-codemod#explanation-of-the-new-es2015-class-transform-with-property-initializers) for this change attempts to convert a `createClass` component to a JavaScript class, with a fallback to `create-react-class` if necessary. It has converted thousands of components internally at Facebook. + +Basic usage: + +```bash +jscodeshift -t react-codemod/transforms/class.js path/to/components +``` + +### Discontinuing support for React Addons + +We're discontinuing active maintenance of React Addons packages. In truth, most of these packages haven't been actively maintained in a long time. They will continue to work indefinitely, but we recommend migrating away as soon as you can to prevent future breakages. + +- **react-addons-create-fragment** – React 16 will have first-class support for fragments, at which point this package won't be necessary. We recommend using arrays of keyed elements instead. +- **react-addons-css-transition-group** - Use [react-transition-group/CSSTransitionGroup](https://github.com/reactjs/react-transition-group) instead. Version 1.1.1 provides a drop-in replacement. +- **react-addons-linked-state-mixin** - Explicitly set the `value` and `onChange` handler instead. +- **react-addons-pure-render-mixin** - Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead. +- **react-addons-shallow-compare** - Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead. +- **react-addons-transition-group** - Use [react-transition-group/TransitionGroup](https://github.com/reactjs/react-transition-group) instead. Version 1.1.1 provides a drop-in replacement. +- **react-addons-update** - Use [immutability-helper](https://github.com/kolodny/immutability-helper) instead, a drop-in replacement. +- **react-linked-input** - Explicitly set the `value` and `onChange` handler instead. + +We're also discontinuing support for the `react-with-addons` UMD build. It will be removed in React 16. + +### React Test Utils + +Currently, the React Test Utils live inside `react-addons-test-utils`. As of 15.5, we're deprecating that package and moving them to `react-dom/test-utils` instead: + +```js +// Before (15.4 and below) +import TestUtils from 'react-addons-test-utils'; + +// After (15.5) +import TestUtils from 'react-dom/test-utils'; +``` + +This reflects the fact that what we call the Test Utils are really a set of APIs that wrap the DOM renderer. + +The exception is shallow rendering, which is not DOM-specific. The shallow renderer has been moved to `react-test-renderer/shallow`. + +```js{2,5} +// Before (15.4 and below) +import { createRenderer } from 'react-addons-test-utils'; + +// After (15.5) +import { createRenderer } from 'react-test-renderer/shallow'; +``` + +--- + +## Acknowledgements + +A special thank you to these folks for transferring ownership of npm package names: + +- [Jason Miller](https://github.com/developit) +- [Aaron Ackerman](https://github.com/aackerman) +- [Vinicius Marson](https://github.com/viniciusmarson) + +--- + +## Installation + +We recommend using [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) for managing front-end dependencies. If you're new to package managers, the [Yarn documentation](https://yarnpkg.com/en/docs/getting-started) is a good place to get started. + +To install React with Yarn, run: + +```bash +yarn add react@15.5.0 react-dom@15.5.0 +``` + +To install React with npm, run: + +```bash +npm install --save react@15.5.0 react-dom@15.5.0 +``` + +We recommend using a bundler like [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time. + +Remember that by default, React runs extra checks and provides helpful warnings in development mode. When deploying your app, make sure to [compile it in production mode](/react/docs/installation.html#development-and-production-versions). + +In case you don't use a bundler, we also provide pre-built bundles in the npm packages which you can [include as script tags](/react/docs/installation.html#using-a-cdn) on your page: + +* **React** + Dev build with warnings: [react/dist/react.js](https://unpkg.com/react@15.5.0/dist/react.js) + Minified build for production: [react/dist/react.min.js](https://unpkg.com/react@15.5.0/dist/react.min.js) +* **React with Add-Ons** + Dev build with warnings: [react/dist/react-with-addons.js](https://unpkg.com/react@15.5.0/dist/react-with-addons.js) + Minified build for production: [react/dist/react-with-addons.min.js](https://unpkg.com/react@15.5.0/dist/react-with-addons.min.js) +* **React DOM** (include React in the page before React DOM) + Dev build with warnings: [react-dom/dist/react-dom.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom.js) + Minified build for production: [react-dom/dist/react-dom.min.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom.min.js) +* **React DOM Server** (include React in the page before React DOM Server) + Dev build with warnings: [react-dom/dist/react-dom-server.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom-server.js) + Minified build for production: [react-dom/dist/react-dom-server.min.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom-server.min.js) + +We've also published version `15.5.0` of the `react`, `react-dom`, and addons packages on npm and the `react` package on bower. + +--- + +## Changelog + +## 15.5.0 (April 7, 2017) + +### React + +* Added a deprecation warning for `React.createClass`. Points users to create-react-class instead. ([@acdlite](https://github.com/acdlite) in [d9a4fa4](https://github.com/facebook/react/commit/d9a4fa4f51c6da895e1655f32255cf72c0fe620e)) +* Added a deprecation warning for `React.PropTypes`. Points users to prop-types instead. ([@acdlite](https://github.com/acdlite) in [043845c](https://github.com/facebook/react/commit/043845ce75ea0812286bbbd9d34994bb7e01eb28)) +* Fixed an issue when using `ReactDOM` together with `ReactDOMServer`. ([@wacii](https://github.com/wacii) in [#9005](https://github.com/facebook/react/pull/9005)) +* Fixed issue with Closure Compiler. ([@anmonteiro](https://github.com/anmonteiro) in [#8895](https://github.com/facebook/react/pull/8895)) +* Another fix for Closure Compiler. ([@Shastel](https://github.com/Shastel) in [#8882](https://github.com/facebook/react/pull/8882)) +* Added component stack info to invalid element type warning. ([@n3tr](https://github.com/n3tr) in [#8495](https://github.com/facebook/react/pull/8495)) + +### React DOM + +* Fixed Chrome bug when backspacing in number inputs. ([@nhunzaker](https://github.com/nhunzaker) in [#7359](https://github.com/facebook/react/pull/7359)) +* Added `react-dom/test-utils`, which exports the React Test Utils. ([@bvaughn](https://github.com/bvaughn)) + +### React Test Renderer + +* Fixed bug where `componentWillUnmount` was not called for children. ([@gre](https://github.com/gre) in [#8512](https://github.com/facebook/react/pull/8512)) +* Added `react-test-renderer/shallow`, which exports the shallow renderer. ([@bvaughn](https://github.com/bvaughn)) + +### React Addons + +* Last release for addons; they will no longer be actively maintained. +* Removed `peerDependencies` so that addons continue to work indefinitely. ([@acdlite](https://github.com/acdlite) and [@bvaughn](https://github.com/bvaughn) in [8a06cd7](https://github.com/facebook/react/commit/8a06cd7a786822fce229197cac8125a551e8abfa) and [67a8db3](https://github.com/facebook/react/commit/67a8db3650d724a51e70be130e9008806402678a)) +* Updated to remove references to `React.createClass` and `React.PropTypes` ([@acdlite](https://github.com/acdlite) in [12a96b9](https://github.com/facebook/react/commit/12a96b94823d6b6de6b1ac13bd576864abd50175)) +* `react-addons-test-utils` is deprecated. Use `react-dom/test-utils` and `react-test-renderer/shallow` instead. ([@bvaughn](https://github.com/bvaughn)) From d3d4b599b9da62178a5cfad621f815ff5127e4cb Mon Sep 17 00:00:00 2001 From: Aaron Ackerman Date: Fri, 7 Apr 2017 22:05:34 -0500 Subject: [PATCH 08/43] Point users to the npm page instead of the github project for prop-types (#9373) --- docs/docs/typechecking-with-proptypes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/typechecking-with-proptypes.md b/docs/docs/typechecking-with-proptypes.md index 63c3241c2e1ce..ce5e0aedee977 100644 --- a/docs/docs/typechecking-with-proptypes.md +++ b/docs/docs/typechecking-with-proptypes.md @@ -7,7 +7,7 @@ redirect_from: --- > Note: -> `React.PropTypes` is deprecated as of React v15.5. Please use [the `prop-types` library instead](https://github.com/aackerman/PropTypes). +> `React.PropTypes` is deprecated as of React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types). As your app grows, you can catch a lot of bugs with typechecking. For some applications, you can use JavaScript extensions like [Flow](https://flowtype.org/) or [TypeScript](https://www.typescriptlang.org/) to typecheck your whole application. But even if you don't use those, React has some built-in typechecking abilities. To run typechecking on the props for a component, you can assign the special `propTypes` property: From 6c8fd16a065913d64306bb7ea2693b135393542d Mon Sep 17 00:00:00 2001 From: Luke Belliveau Date: Sun, 9 Apr 2017 14:37:41 -0500 Subject: [PATCH 09/43] Amended implementation-notes.md with link to Dan Abramov's post describing difference between React components, elements, and instances (#9388) * Amended implementation-notes.md to include a link to a blog post by Dan Abramov, explaining the difference between components, elements, and instances. An understanding of this distinction is crucial in tracing through Implementation pseudocode, and reading Dan's blog first may ease newcomers into understanding the implementation. * adjusted wording to maintain stylistic consistency with rest of content, per @aweary's request --- docs/contributing/implementation-notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/implementation-notes.md b/docs/contributing/implementation-notes.md index 2252a006cac71..2309dd721cc1b 100644 --- a/docs/contributing/implementation-notes.md +++ b/docs/contributing/implementation-notes.md @@ -11,6 +11,8 @@ This section is a collection of implementation notes for the [stack reconciler]( It is very technical and assumes a strong understanding of React public API as well as how it's divided into core, renderers, and the reconciler. If you're not very familiar with the React codebase, read [the codebase overview](/react/contributing/codebase-overview.html) first. +It also assumes an understanding of the [differences between React components, their instances, and elements](/react/blog/2015/12/18/react-components-elements-and-instances.html). + The stack reconciler is powering all the React production code today. It is located in [`src/renderers/shared/stack/reconciler`](https://github.com/facebook/react/tree/master/src/renderers/shared/stack) and is used by both React DOM and React Native. ### Video: Building React from Scratch From 457b812c262931239682e5cbb57c5bd5900d218b Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 10 Apr 2017 22:01:56 +0100 Subject: [PATCH 10/43] Fix ReactARTStack bundles to not include DOM Stack inside (#9394) * Move ReactDOMFrameScheduling.js to shared (between dom and art) * Fix ReactARTStack bundles to not include DOM Stack inside --- scripts/rollup/build.js | 9 +++- scripts/rollup/bundles.js | 6 +-- scripts/rollup/modules.js | 8 --- scripts/rollup/results.json | 50 +++++++++---------- .../ReactDOMFrameScheduling.js | 0 src/test/ReactTestUtils.js | 2 +- 6 files changed, 36 insertions(+), 39 deletions(-) rename src/renderers/{dom/fiber => shared}/ReactDOMFrameScheduling.js (100%) diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index b557a11926504..7f3055b099239 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -246,12 +246,19 @@ function getPlugins( manglePropertiesOnProd ) { const plugins = [ - replace(Modules.getDefaultReplaceModules(bundleType)), babel(updateBabelConfig(babelOpts, bundleType)), alias( Modules.getAliases(paths, bundleType, isRenderer, argv.extractErrors) ), ]; + + const replaceModules = Modules.getDefaultReplaceModules(bundleType); + // We have to do this check because Rollup breaks on empty object. + // TODO: file an issue with rollup-plugin-replace. + if (Object.keys(replaceModules).length > 0) { + plugins.unshift(replace(replaceModules)); + } + switch (bundleType) { case UMD_DEV: case NODE_DEV: diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index fc221c5a5809c..69b04f0b73d0f 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -169,6 +169,7 @@ const bundles = [ 'art/modes/current', 'art/modes/fast-noSideEffects', 'art/core/transform', + 'react-dom', ], fbEntry: 'src/renderers/art/ReactARTStack.js', hasteName: 'ReactARTStack', @@ -177,8 +178,6 @@ const bundles = [ manglePropertiesOnProd: false, name: 'react-art', paths: [ - // TODO: it relies on ReactDOMFrameScheduling. Need to move to shared/? - 'src/renderers/dom/**/*.js', 'src/renderers/art/**/*.js', 'src/renderers/shared/**/*.js', @@ -204,6 +203,7 @@ const bundles = [ 'art/modes/current', 'art/modes/fast-noSideEffects', 'art/core/transform', + 'react-dom', ], fbEntry: 'src/renderers/art/ReactARTFiber.js', hasteName: 'ReactARTFiber', @@ -212,8 +212,6 @@ const bundles = [ manglePropertiesOnProd: false, name: 'react-art', paths: [ - // TODO: it relies on ReactDOMFrameScheduling. Need to move to shared/? - 'src/renderers/dom/**/*.js', 'src/renderers/art/**/*.js', 'src/renderers/shared/**/*.js', diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index e6b1904a468d0..801b94e3c4f43 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -171,13 +171,6 @@ function getInternalModules() { }; } -function replaceInternalModules() { - // we inline these modules in the bundles rather than leave them as external - return { - "'react-dom'": `'${resolve('./src/renderers/dom/ReactDOM.js')}'`, - }; -} - function getFbjsModuleAliases(bundleType) { switch (bundleType) { case UMD_DEV: @@ -253,7 +246,6 @@ function getAliases(paths, bundleType, isRenderer, extractErrors) { function getDefaultReplaceModules(bundleType) { return Object.assign( {}, - replaceInternalModules(), replaceFbjsModuleAliases(bundleType), replaceDevOnlyStubbedModules(bundleType) ); diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index 9d4a85e8cc540..88406fe9dfaaf 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,5 +1,5 @@ { - "branch": "remove-lib-in-source", + "branch": "bundle-fixes", "bundleSizes": { "react.development.js (UMD_DEV)": { "size": 116098, @@ -26,12 +26,12 @@ "gzip": 33035 }, "react-art.development.js (UMD_DEV)": { - "size": 339599, - "gzip": 75952 + "size": 339929, + "gzip": 76018 }, "react-art.production.min.js (UMD_PROD)": { - "size": 94939, - "gzip": 28977 + "size": 95013, + "gzip": 28991 }, "react.development.js (NODE_DEV)": { "size": 109110, @@ -90,28 +90,28 @@ "gzip": 80424 }, "ReactARTStack-dev.js (FB_DEV)": { - "size": 492651, - "gzip": 118470 + "size": 141589, + "gzip": 32280 }, "ReactARTStack-prod.js (FB_PROD)": { - "size": 365055, - "gzip": 87582 + "size": 99762, + "gzip": 22576 }, "react-art.development.js (NODE_DEV)": { - "size": 264816, - "gzip": 56881 + "size": 265123, + "gzip": 56951 }, "react-art.production.min.js (NODE_PROD)": { - "size": 56517, - "gzip": 17109 + "size": 56591, + "gzip": 17132 }, "ReactARTFiber-dev.js (FB_DEV)": { - "size": 263951, - "gzip": 56683 + "size": 264301, + "gzip": 56758 }, "ReactARTFiber-prod.js (FB_PROD)": { - "size": 205154, - "gzip": 43017 + "size": 205292, + "gzip": 43132 }, "ReactNativeStack.js (RN)": { "size": 233993, @@ -122,20 +122,20 @@ "gzip": 84001 }, "ReactTestRendererFiber-dev.js (FB_DEV)": { - "size": 261860, - "gzip": 55645 + "size": 262210, + "gzip": 55722 }, "ReactTestRendererStack-dev.js (FB_DEV)": { - "size": 151102, - "gzip": 34699 + "size": 151425, + "gzip": 34728 }, "react-noop-renderer.development.js (NODE_DEV)": { - "size": 253895, - "gzip": 53629 + "size": 254207, + "gzip": 53701 }, "react-test-renderer.development.js (NODE_DEV)": { - "size": 262734, - "gzip": 55847 + "size": 263041, + "gzip": 55919 } } } \ No newline at end of file diff --git a/src/renderers/dom/fiber/ReactDOMFrameScheduling.js b/src/renderers/shared/ReactDOMFrameScheduling.js similarity index 100% rename from src/renderers/dom/fiber/ReactDOMFrameScheduling.js rename to src/renderers/shared/ReactDOMFrameScheduling.js diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index d0ca2fe4063e0..f320be4bd12b5 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -17,7 +17,7 @@ var EventPluginRegistry = require('EventPluginRegistry'); var EventPropagators = require('EventPropagators'); var React = require('react'); var ReactControlledComponent = require('ReactControlledComponent'); -var ReactDOM = require('react-dom'); +var ReactDOM = require('ReactDOM'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactFiberTreeReflection = require('ReactFiberTreeReflection'); From c2309bf4b58548872c819bd94859ad0a39e17632 Mon Sep 17 00:00:00 2001 From: Maciej Kasprzyk Date: Mon, 10 Apr 2017 23:26:09 +0200 Subject: [PATCH 11/43] Delete examples dir from codebase overview (#9397) Removes doc about folder that no longer exists. --- docs/contributing/codebase-overview.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/contributing/codebase-overview.md b/docs/contributing/codebase-overview.md index 045f2c9030231..637c4893241ec 100644 --- a/docs/contributing/codebase-overview.md +++ b/docs/contributing/codebase-overview.md @@ -66,7 +66,6 @@ After cloning the [React repository](https://github.com/facebook/react), you wil * [`src`](https://github.com/facebook/react/tree/master/src) is the source code of React. **If your change is related to the code, `src` is where you'll spend most of your time.** * [`docs`](https://github.com/facebook/react/tree/master/docs) is the React documentation website. When you change APIs, make sure to update the relevant Markdown files. -* [`examples`](https://github.com/facebook/react/tree/master/examples) contains a few small React demos with different build setups. * [`packages`](https://github.com/facebook/react/tree/master/packages) contains metadata (such as `package.json`) for all packages in the React repository. Nevertheless, their source code is still located inside [`src`](https://github.com/facebook/react/tree/master/src). * `build` is the build output of React. It is not in the repository but it will appear in your React clone after you [build it](/react/contributing/how-to-contribute.html#development-workflow) for the first time. From 5cfaa7cf68564b8d96c94fa0d45e7feb6dc80895 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 21 Mar 2017 18:36:38 -0700 Subject: [PATCH 12/43] Delete createClass Remove createClass from isomorphic package --- src/isomorphic/React.js | 2 - src/isomorphic/classic/class/ReactClass.js | 833 ------------------ .../classic/class/__tests__/ReactBind-test.js | 152 ---- .../class/__tests__/ReactBindOptout-test.js | 206 ----- .../class/__tests__/ReactClass-test.js | 348 -------- .../class/__tests__/ReactClassMixin-test.js | 532 ----------- 6 files changed, 2073 deletions(-) delete mode 100644 src/isomorphic/classic/class/ReactClass.js delete mode 100644 src/isomorphic/classic/class/__tests__/ReactBind-test.js delete mode 100644 src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js delete mode 100644 src/isomorphic/classic/class/__tests__/ReactClass-test.js delete mode 100644 src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index 5e57605f1c0fc..a37649a3197b6 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -13,7 +13,6 @@ var ReactBaseClasses = require('ReactBaseClasses'); var ReactChildren = require('ReactChildren'); -var ReactClass = require('ReactClass'); var ReactDOMFactories = require('ReactDOMFactories'); var ReactElement = require('ReactElement'); var ReactPropTypes = require('ReactPropTypes'); @@ -75,7 +74,6 @@ var React = { // Classic PropTypes: ReactPropTypes, - createClass: ReactClass.createClass, createFactory: createFactory, createMixin: createMixin, diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js deleted file mode 100644 index fb1c07ec08b75..0000000000000 --- a/src/isomorphic/classic/class/ReactClass.js +++ /dev/null @@ -1,833 +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. - * - * @providesModule ReactClass - */ - -'use strict'; - -var ReactBaseClasses = require('ReactBaseClasses'); -var ReactElement = require('ReactElement'); -var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); - -var emptyObject = require('fbjs/lib/emptyObject'); -var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); - -var ReactComponent = ReactBaseClasses.Component; - -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'; - -/** - * 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} - * @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, 'child context'); - } - 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: string) { - 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', - 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.\n\nSee %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.\n\nSee %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, 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, -); - -/** - * 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/react-api.html#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 = []; - - 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.', - ); - - 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', - ); - } - - // 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; - }, -}; - -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 051db5a8fed29..0000000000000 --- a/src/isomorphic/classic/class/__tests__/ReactBind-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 - */ -/*global global:true*/ -'use strict'; - -var React = require('react'); -var ReactTestUtils = require('ReactTestUtils'); - -// 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 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - var instance2 = ReactTestUtils.renderIntoDocument(); - var rendered2 = instance2.refs.child; - - expect(function() { - var badIdea = instance1.badIdeas.badBind; - badIdea(); - }).toThrow(); - - expect(instance1.onClick).not.toBe(instance2.onClick); - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.click(rendered2); - expect(mouseDidClick.mock.instances.length).toBe(2); - expect(mouseDidClick.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOver(rendered1); - expect(mouseDidEnter.mock.instances.length).toBe(1); - expect(mouseDidEnter.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOver(rendered2); - expect(mouseDidEnter.mock.instances.length).toBe(2); - expect(mouseDidEnter.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOut(rendered1); - expect(mouseDidLeave.mock.instances.length).toBe(1); - expect(mouseDidLeave.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOut(rendered2); - expect(mouseDidLeave.mock.instances.length).toBe(2); - expect(mouseDidLeave.mock.instances[1]).toBe(instance2); - }); - - it('works with mixins', () => { - var mouseDidClick = jest.fn(); - - var TestMixin = { - onClick: mouseDidClick, - }; - - var TestBindComponent = React.createClass({ - mixins: [TestMixin], - - render: function() { - return
; - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - }); - - it('warns if you try to bind to this', () => { - spyOn(console, 'error'); - - var TestBindComponent = React.createClass({ - handleClick: function() {}, - render: function() { - return
; - }, - }); - - ReactTestUtils.renderIntoDocument(); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(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.\n\nSee 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(); - - expectDev(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 086329338fa4d..0000000000000 --- a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js +++ /dev/null @@ -1,206 +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'); - -// 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 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - var instance2 = ReactTestUtils.renderIntoDocument(); - var rendered2 = instance2.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.click(rendered2); - expect(mouseDidClick.mock.instances.length).toBe(2); - expect(mouseDidClick.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOver(rendered1); - expect(mouseDidEnter.mock.instances.length).toBe(1); - expect(mouseDidEnter.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOver(rendered2); - expect(mouseDidEnter.mock.instances.length).toBe(2); - expect(mouseDidEnter.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOut(rendered1); - expect(mouseDidLeave.mock.instances.length).toBe(1); - expect(mouseDidLeave.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOut(rendered2); - expect(mouseDidLeave.mock.instances.length).toBe(2); - expect(mouseDidLeave.mock.instances[1]).toBe(instance2); - }); - - 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 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - var instance2 = ReactTestUtils.renderIntoDocument(); - var rendered2 = instance2.refs.child; - - expect(function() { - var badIdea = instance1.badIdeas.badBind; - badIdea(); - }).toThrow(); - - expect(instance1.onClick).toBe(instance2.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 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - }); - - 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 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - }); - - 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(); - - expectDev(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(); - - expectDev(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 deleted file mode 100644 index 4ab5ad7dac01e..0000000000000 --- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js +++ /dev/null @@ -1,348 +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; - -describe('ReactClass-spec', () => { - beforeEach(() => { - React = require('react'); - ReactDOM = require('react-dom'); - ReactTestUtils = require('ReactTestUtils'); - }); - - 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}; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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}; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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}; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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
; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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
; - }, - }); - expectDev(console.error.calls.count()).toBe(2); - expectDev(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
; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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: React.PropTypes.string, - }, - contextTypes: { - foo: React.PropTypes.string, - }, - childContextTypes: { - foo: React.PropTypes.string, - }, - render: function() { - return
; - }, - }); - expectDev(console.error.calls.count()).toBe(4); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'createClass(...): `mixins` is now a static property and should ' + - 'be defined inside "statics".', - ); - expectDev(console.error.calls.argsFor(1)[0]).toBe( - 'createClass(...): `propTypes` is now a static property and should ' + - 'be defined inside "statics".', - ); - expectDev(console.error.calls.argsFor(2)[0]).toBe( - 'createClass(...): `contextTypes` is now a static property and ' + - 'should be defined inside "statics".', - ); - expectDev(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: React.PropTypes.string, - }, - getInitialState() { - return {className: this.context.className}; - }, - render() { - return ; - }, - }); - - var Outer = React.createClass({ - childContextTypes: { - className: React.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(); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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/__tests__/ReactClassMixin-test.js b/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js deleted file mode 100644 index 2f079a69fc19d..0000000000000 --- a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js +++ /dev/null @@ -1,532 +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 = ReactTestUtils.renderIntoDocument(); - 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 ; - }, - }); - expect(function() { - ReactTestUtils.renderIntoDocument(); - }).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 ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(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 ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(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 ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(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 ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(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 ; - }, - }); - ReactTestUtils.renderIntoDocument(); - }); - - 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 ; - }, - }); - ReactTestUtils.renderIntoDocument(); - }); - - 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 = ReactTestUtils.renderIntoDocument(); - 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 = ReactTestUtils.renderIntoDocument(); - 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 = ReactTestUtils.renderIntoDocument(); - expect(instance.state).toEqual({foo: 'bar', x: true}); - }); -}); From 087fe88f20102454ec2581368dfb152abf3d7c20 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 21 Mar 2017 18:37:16 -0700 Subject: [PATCH 13/43] Rewrite Stack implementation of ReactART using plain classes instead of createClass --- src/renderers/art/ReactARTStack.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/renderers/art/ReactARTStack.js b/src/renderers/art/ReactARTStack.js index db1d22a885e86..26e3ff92e82f6 100644 --- a/src/renderers/art/ReactARTStack.js +++ b/src/renderers/art/ReactARTStack.js @@ -170,12 +170,8 @@ const ContainerMixin = Object.assign({}, ReactMultiChild, { // 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); @@ -189,9 +185,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 || this.props.height != oldProps.height @@ -220,13 +216,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 @@ -246,8 +242,10 @@ const Surface = React.createClass({ title={props.title} /> ); - }, -}); + } +} +Surface.displayName = 'Surface'; +Object.assign(Surface.prototype, ContainerMixin); // Various nodes that can go into a surface From c76a4eaa2aab1a10825c51f8e9c7baccc54ef56b Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 21 Mar 2017 18:38:15 -0700 Subject: [PATCH 14/43] Update tests to use plain JavaScript classes Tests that rely on replaceState or isMounted use updater.enqueueReplaceState and updater.isMounted instead. --- mocks/ReactElementTestChild.js | 8 +- mocks/ReactMockedComponentTestComponent.js | 21 +- scripts/fiber/tests-passing.txt | 61 +---- .../__tests__/ReactContextValidator-test.js | 215 +++++++++--------- .../element/__tests__/ReactElement-test.js | 214 ++++++----------- .../__tests__/ReactElementClone-test.js | 191 ++++++++-------- .../__tests__/ReactElementValidator-test.js | 187 +++++++-------- .../ReactPropTypesProduction-test.js | 11 +- .../__tests__/ReactComponentLifeCycle-test.js | 137 ++++++----- .../__tests__/ReactComponentTreeHook-test.js | 11 +- .../__tests__/ReactCompositeComponent-test.js | 95 ++------ .../ReactCompositeComponentState-test.js | 66 +++--- .../__tests__/ReactMultiChild-test.js | 50 ++-- src/renderers/__tests__/ReactPerf-test.js | 20 +- .../__tests__/ReactStatelessComponent-test.js | 19 +- src/renderers/__tests__/ReactUpdates-test.js | 95 ++------ .../__tests__/ReactDOMComponent-test.js | 42 ++-- .../dom/shared/__tests__/ReactMount-test.js | 12 +- .../__tests__/ReactServerRendering-test.js | 26 --- .../__tests__/BeforeInputEventPlugin-test.js | 8 +- .../fiber/__tests__/ReactIncremental-test.js | 14 +- .../ReactIncrementalReflection-test.js | 44 ++-- .../__tests__/ReactIncrementalUpdates-test.js | 46 ++-- src/test/__tests__/ReactTestUtils-test.js | 10 +- 24 files changed, 663 insertions(+), 940 deletions(-) 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/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 0c658781d6468..cf40f4bb6cd81 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -89,64 +89,10 @@ src/isomorphic/classic/__tests__/ReactContextValidator-test.js * should warn (but not error) if getChildContext method is missing * should pass parent context if getChildContext method is missing -src/isomorphic/classic/class/__tests__/ReactBind-test.js -* Holds reference to instance -* works with mixins -* warns if you try to bind to this -* does not warn if you pass an auto-bound method to setState - -src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js -* should work with manual binding -* should not hold reference to instance -* works with mixins that have not opted out of autobinding -* works with mixins that have opted out of autobinding -* does not warn if you try to bind to this -* does not warn if you pass an manually bound method to setState - -src/isomorphic/classic/class/__tests__/ReactClass-test.js -* should throw when `render` is not specified -* should copy `displayName` onto the Constructor -* should copy prop types onto the Constructor -* should warn on invalid prop types -* should warn on invalid context types -* should throw on invalid child context types -* should warn when mispelling shouldComponentUpdate -* should warn when mispelling componentWillReceiveProps -* should throw if a reserved property is in statics -* should support statics -* should work with object getInitialState() return values -* renders based on context getInitialState -* should throw with non-object getInitialState() return values -* should work with a null getInitialState() return value -* should throw when using legacy factories - -src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js -* should support merging propTypes and statics -* should support chaining delegate functions -* should chain functions regardless of spec property order -* should validate prop types via mixins -* should override mixin prop types with class prop types -* should support mixins with getInitialState() -* should throw with conflicting getInitialState() methods -* should not mutate objects returned by getInitialState() -* should support statics in mixins -* should throw if mixins override each others' statics -* should throw if mixins override functions in statics -* should warn if the mixin is undefined -* should warn if the mixin is null -* should warn if an undefined mixin is included in another mixin -* should warn if a null mixin is included in another mixin -* should throw if the mixin is a React component -* should throw if the mixin is a React component class -* should have bound the mixin methods to the component -* should include the mixin keys in even if their values are falsy -* should work with a null getInitialState return value and a mixin - src/isomorphic/classic/element/__tests__/ReactElement-test.js * uses the fallback value when in an environment without Symbol * returns a complete element according to spec -* should warn when `key` is being accessed on createClass element -* should warn when `key` is being accessed on ES class element +* should warn when `key` is being accessed on composite element * should warn when `key` is being accessed on a host element * should warn when `ref` is being accessed * allows a string to be passed as the type @@ -165,7 +111,6 @@ src/isomorphic/classic/element/__tests__/ReactElement-test.js * merges rest arguments onto the children prop in an array * allows static methods to be called using the type property * identifies valid elements -* allows the use of PropTypes validators in statics * is indistinguishable from a plain object * should use default prop value when removing a prop * should normalize props with default values @@ -495,8 +440,6 @@ src/renderers/__tests__/ReactCompositeComponent-test.js * should react to state changes from callbacks * should rewire refs when rendering to different child types * should not cache old DOM nodes when switching constructors -* should auto bind methods and values correctly -* should not pass this to getDefaultProps * should use default values for undefined props * should not mutate passed-in props object * should warn about `forceUpdate` on unmounted components @@ -718,7 +661,6 @@ src/renderers/__tests__/ReactUpdates-test.js * does not call render after a component as been deleted * marks top-level updates * throws in setState if the update callback is not a function -* throws in replaceState if the update callback is not a function * throws in forceUpdate if the update callback is not a function * does not update one component twice in a batch (#2410) * does not update one component twice in a batch (#6371) @@ -1299,7 +1241,6 @@ src/renderers/dom/shared/__tests__/ReactServerRendering-test.js * allows setState in componentWillMount without using DOM * renders components with different batching strategies * warns with a no-op when an async setState is triggered -* warns with a no-op when an async replaceState is triggered * warns with a no-op when an async forceUpdate is triggered * should warn when children are mutated during render diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js index dfd0f21809005..c05c6a305ca7f 100644 --- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js +++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js @@ -38,33 +38,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, - }, + } + } + Component.contextTypes = { + foo: React.PropTypes.string, + }; - getChildContext: function() { + 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( , @@ -77,47 +75,45 @@ describe('ReactContextValidator', () => { var actualShouldComponentUpdate; var actualComponentWillUpdate; - 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, - }, + } + } + Parent.childContextTypes = { + foo: React.PropTypes.string.isRequired, + bar: React.PropTypes.string.isRequired, + }; - componentWillReceiveProps: function(nextProps, nextContext) { + 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; - }, + } - render: function() { + render() { return
; - }, - }); + } + } + Component.contextTypes = { + foo: React.PropTypes.string, + }; var container = document.createElement('div'); ReactDOM.render(, container); @@ -130,37 +126,36 @@ describe('ReactContextValidator', () => { it('should pass previous context to lifecycles', () => { 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, - }, + } + } + Parent.childContextTypes = { + foo: React.PropTypes.string.isRequired, + bar: React.PropTypes.string.isRequired, + }; - componentDidUpdate: function(prevProps, prevState, prevContext) { + class Component extends React.Component { + componentDidUpdate(prevProps, prevState, prevContext) { actualComponentDidUpdate = prevContext; - }, + } - render: function() { + render() { return
; - }, - }); + } + } + Component.contextTypes = { + foo: React.PropTypes.string, + }; + var container = document.createElement('div'); ReactDOM.render(, container); @@ -171,15 +166,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(); @@ -191,21 +185,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( , @@ -214,21 +207,20 @@ describe('ReactContextValidator', () => { // Previous call should not error expectDev(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( , @@ -247,20 +239,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(); expectDev(console.error.calls.count()).toBe(1); @@ -362,16 +353,16 @@ describe('ReactContextValidator', () => { } var childContext; - var ChildContextConsumer = React.createClass({ - contextTypes: { - bar: React.PropTypes.string.isRequired, - foo: React.PropTypes.string.isRequired, - }, - render: function() { + class ChildContextConsumer extends React.Component { + render() { childContext = this.context; return
; - }, - }); + } + } + ChildContextConsumer.contextTypes = { + bar: React.PropTypes.string.isRequired, + foo: React.PropTypes.string.isRequired, + }; ReactTestUtils.renderIntoDocument(); expect(childContext.bar).toBeUndefined(); diff --git a/src/isomorphic/classic/element/__tests__/ReactElement-test.js b/src/isomorphic/classic/element/__tests__/ReactElement-test.js index 27bd222be8ffd..d03f176ba6ba0 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElement-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElement-test.js @@ -34,11 +34,11 @@ describe('ReactElement', () => { ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); // 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(() => { @@ -59,37 +59,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 ( -
- - - -
- ); - }, - }); - expectDev(console.error.calls.count()).toBe(0); - ReactDOM.render(, container); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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 { @@ -97,8 +67,8 @@ describe('ReactElement', () => { return
{this.props.key}
; } } - var Parent = React.createClass({ - render: function() { + class Parent extends React.Component { + render() { return (
@@ -106,9 +76,9 @@ describe('ReactElement', () => {
); - }, - }); - expectDev(console.error.calls.count()).toBe(0); + } + } + expect(console.error.calls.count()).toBe(0); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toContain( @@ -136,21 +106,21 @@ 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 (
); - }, - }); - expectDev(console.error.calls.count()).toBe(0); + } + } + expect(console.error.calls.count()).toBe(0); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toContain( @@ -257,12 +227,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), @@ -324,19 +294,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'); @@ -346,11 +309,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); expect(React.isValidElement(React.createElement(Component))).toEqual(true); @@ -367,21 +330,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', () => { @@ -393,14 +341,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( @@ -416,14 +362,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), @@ -437,8 +381,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() { @@ -447,17 +391,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() { @@ -467,8 +410,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(''); @@ -476,11 +420,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(); expectDev(console.error.calls.count()).toBe(0); @@ -508,11 +452,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); expect(React.isValidElement(React.createElement(Component))).toEqual(true); @@ -544,16 +488,16 @@ 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(); + } + }; + instance = ReactTestUtils.renderIntoDocument(); }); it('should scry children but cannot', () => { @@ -580,14 +524,11 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => { var factory, instance; beforeEach(() => { var childFactory = React.createFactory(Child); - var Parent = React.createClass({ - render: function() { - return React.DOM.div( - {}, - childFactory({ref: 'child', foo: 'foo value'}, 'children value'), - ); - }, - }); + 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()); }); @@ -615,18 +556,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() { - return React.DOM.div( - {}, - React.createElement( - Child, - {ref: 'child', foo: 'foo value'}, - 'children value', - ), - ); - }, - }); + 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 b4eaaa0765ef7..f1baac684c376 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, @@ -175,41 +175,39 @@ describe('ReactElementClone', () => { }); it('should support keys and refs', () => { - var Parent = React.createClass({ - render: function() { - var clone = React.cloneElement(this.props.children, { - key: 'xyz', - ref: 'xyz', - }); + 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(); @@ -217,12 +215,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'}), @@ -230,14 +228,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}); @@ -289,26 +285,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() { - return React.createElement(Parent, { - child: React.createElement(Component, {color: 'red'}), - }); - }, - }); + } + } + class GrandParent extends React.Component { + render() { + return React.createElement( + Parent, + { child: React.createElement(Component, {color: 'red'}) } + ); + } + } ReactTestUtils.renderIntoDocument(React.createElement(GrandParent)); expectDev(console.error.calls.count()).toBe(1); expectDev(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 c9dbf7cc8f8ed..8b88e5a44dcd6 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('react-dom'); 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() { - return InnerComponent({childSet: [Component(), Component()]}); - }, - }); + class ComponentWrapper extends React.Component { + render() { + return InnerComponent({childSet: [Component(), Component()] }); + } + } ReactTestUtils.renderIntoDocument(React.createElement(ComponentWrapper)); @@ -83,12 +81,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 = [
,
]; ReactTestUtils.renderIntoDocument({divs}); @@ -119,23 +115,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(); @@ -154,16 +144,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( @@ -255,19 +243,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)); expectDev(console.error.calls.argsFor(0)[0]).toBe( 'Warning: Failed prop type: ' + @@ -325,11 +309,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( @@ -349,15 +331,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)); @@ -372,15 +352,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}), @@ -397,14 +375,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)); ReactTestUtils.renderIntoDocument( @@ -437,14 +415,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'}}), @@ -462,11 +441,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); expectDev(console.error.calls.count()).toBe(1); @@ -481,14 +458,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/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 22d0ba1996477..33ccb85bd86a7 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -205,13 +205,10 @@ describe('ReactPropTypesProduction', function() { it('should not have been called', function() { var spy = jest.fn(); - var Component = React.createClass({ - propTypes: {num: spy}, - - render: function() { - return
; - }, - }); + function Component() { + return
; + } + Component.propTypes = {num: spy}; var instance = ; ReactTestUtils.renderIntoDocument(instance); diff --git a/src/renderers/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/__tests__/ReactComponentLifeCycle-test.js index e65acdfbd139c..ab13a65b44c32 100644 --- a/src/renderers/__tests__/ReactComponentLifeCycle-test.js +++ b/src/renderers/__tests__/ReactComponentLifeCycle-test.js @@ -225,23 +225,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(); - return
; - }, - }); + 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(); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toContain( @@ -251,23 +256,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(); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toContain( @@ -276,38 +286,38 @@ describe('ReactComponentLifeCycle', () => { }); it('isMounted should return false when unmounted', () => { - var Component = React.createClass({ - render: function() { - return
; - }, - }); + 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(); expectDev(console.error.calls.count()).toBe(1); @@ -513,30 +523,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'); log = []; diff --git a/src/renderers/__tests__/ReactComponentTreeHook-test.js b/src/renderers/__tests__/ReactComponentTreeHook-test.js index 2182aabf38c95..1ae443f731fea 100644 --- a/src/renderers/__tests__/ReactComponentTreeHook-test.js +++ b/src/renderers/__tests__/ReactComponentTreeHook-test.js @@ -41,8 +41,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; + } expectDev(getAddendum()).toBe(''); expectDev(getAddendum(
)).toBe('\n in div (at **)'); diff --git a/src/renderers/__tests__/ReactCompositeComponent-test.js b/src/renderers/__tests__/ReactCompositeComponent-test.js index 7a7be1a0d1926..d3ead32dc5906 100644 --- a/src/renderers/__tests__/ReactCompositeComponent-test.js +++ b/src/renderers/__tests__/ReactCompositeComponent-test.js @@ -166,64 +166,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(); - - expectDev(console.error.calls.count()).toBe(1); - var explicitlyBound = mountedInstance.methodToBeExplicitlyBound.bind( - mountedInstance, - ); - expectDev(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'}; @@ -1204,17 +1146,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); }); @@ -1226,21 +1168,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); @@ -1254,14 +1197,14 @@ describe('ReactCompositeComponent', () => { var fifthState = new NotActuallyImmutable('fifth'); ReactDOM.unstable_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'); ReactDOM.unstable_batchedUpdates(function() { - moo.replaceState(sixthState); + moo._replaceState(sixthState); moo.setState({str: 'seventh'}); }); expect(moo.state.str).toBe('seventh'); diff --git a/src/renderers/__tests__/ReactCompositeComponentState-test.js b/src/renderers/__tests__/ReactCompositeComponentState-test.js index 6bed124cfd919..ca88e476736e8 100644 --- a/src/renderers/__tests__/ReactCompositeComponentState-test.js +++ b/src/renderers/__tests__/ReactCompositeComponentState-test.js @@ -24,34 +24,34 @@ describe('ReactCompositeComponent-state', () => { ReactDOM = require('react-dom'); ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); - 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); @@ -72,25 +72,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); @@ -103,28 +105,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/__tests__/ReactMultiChild-test.js b/src/renderers/__tests__/ReactMultiChild-test.js index 2a78651a4dcd7..d3c408f7ac203 100644 --- a/src/renderers/__tests__/ReactMultiChild-test.js +++ b/src/renderers/__tests__/ReactMultiChild-test.js @@ -35,14 +35,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); @@ -67,13 +67,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); @@ -95,13 +95,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() { @@ -132,13 +132,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/__tests__/ReactPerf-test.js b/src/renderers/__tests__/ReactPerf-test.js index f01b3193d0fdb..a610e9523d497 100644 --- a/src/renderers/__tests__/ReactPerf-test.js +++ b/src/renderers/__tests__/ReactPerf-test.js @@ -64,16 +64,16 @@ describeStack('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/__tests__/ReactStatelessComponent-test.js b/src/renderers/__tests__/ReactStatelessComponent-test.js index b3cacfbf09ec6..b1cc7ba9d0838 100644 --- a/src/renderers/__tests__/ReactStatelessComponent-test.js +++ b/src/renderers/__tests__/ReactStatelessComponent-test.js @@ -249,15 +249,14 @@ describe('ReactStatelessComponent', () => { it('deduplicates ref warnings based on element or owner', () => { spyOn(console, 'error'); - // Prevent the Babel transform adding a displayName. - var createClassWithoutDisplayName = React.createClass; - // When owner uses JSX, we can use exact line location to dedupe warnings - var AnonymousParentUsingJSX = createClassWithoutDisplayName({ + class AnonymousParentUsingJSX extends React.Component { render() { return {}} />; - }, - }); + } + } + Object.defineProperty(AnonymousParentUsingJSX, 'name', {value: undefined}); + const instance1 = ReactTestUtils.renderIntoDocument( , ); @@ -273,14 +272,16 @@ describe('ReactStatelessComponent', () => { console.error.calls.reset(); // When owner doesn't use JSX, and is anonymous, we warn once per internal instance. - var AnonymousParentNotUsingJSX = createClassWithoutDisplayName({ + class AnonymousParentNotUsingJSX extends React.Component { render() { return React.createElement(StatelessComponent, { name: 'A', ref: () => {}, }); - }, - }); + } + } + Object.defineProperty(AnonymousParentNotUsingJSX, 'name', {value: undefined}); + const instance2 = ReactTestUtils.renderIntoDocument( , ); diff --git a/src/renderers/__tests__/ReactUpdates-test.js b/src/renderers/__tests__/ReactUpdates-test.js index 982881b52181e..bba996cbc65c4 100644 --- a/src/renderers/__tests__/ReactUpdates-test.js +++ b/src/renderers/__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); @@ -913,52 +906,6 @@ describe('ReactUpdates', () => { expect(console.error.calls.count()).toBe(3); }); - it('throws in replaceState if the update callback is not a function', () => { - spyOn(console, 'error'); - - 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( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: no', - ); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'replaceState(...): Expected the last optional `callback` argument to be ' + - 'a function. Instead received: no.', - ); - component = ReactTestUtils.renderIntoDocument(); - expect(() => component.replaceState({}, {foo: 'bar'})).toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', - ); - expectDev(console.error.calls.argsFor(1)[0]).toContain( - 'replaceState(...): Expected the last optional `callback` argument to be ' + - 'a function. Instead received: [object Object].', - ); - component = ReactTestUtils.renderIntoDocument(); - expect(() => component.replaceState({}, new Foo())).toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', - ); - expectDev(console.error.calls.argsFor(2)[0]).toContain( - 'replaceState(...): Expected the last optional `callback` argument to be ' + - 'a function. Instead received: [object Object].', - ); - expect(console.error.calls.count()).toBe(3); - }); - it('throws in forceUpdate if the update callback is not a function', () => { spyOn(console, 'error'); diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index 7a8c73ddc79e7..34f03e5be0dac 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -868,11 +868,11 @@ describe('ReactDOMComponent', () => { container.shadyRoot = {}; return container; }; - var ShadyComponent = React.createClass({ + class ShadyComponent extends React.Component { render() { return ; - }, - }); + } + } var node = document.createElement('div'); ReactDOM.render(, node); expectDev(console.error.calls.count()).toBe(1); @@ -1350,12 +1350,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() { @@ -1369,12 +1369,12 @@ describe('ReactDOMComponent', () => { } } - var Viz1 = React.createClass({ - render: () =>
, - }); - var App1 = React.createClass({ - render: () => , - }); + function Viz1() { + return
; + } + function App1() { + return ; + } ReactTestUtils.renderIntoDocument(); expectDev(console.error.calls.count()).toBe(1); expectDev( @@ -1389,12 +1389,12 @@ describe('ReactDOMComponent', () => { : 'See Viz1 > table > FancyRow > Row > tr.', ); - var Viz2 = React.createClass({ - render: () => , - }); - var App2 = React.createClass({ - render: () => , - }); + function Viz2() { + return ; + } + function App2() { + return ; + } ReactTestUtils.renderIntoDocument(); expectDev(console.error.calls.count()).toBe(2); expectDev( diff --git a/src/renderers/dom/shared/__tests__/ReactMount-test.js b/src/renderers/dom/shared/__tests__/ReactMount-test.js index 3f49f1845657c..fb942d15b8aec 100644 --- a/src/renderers/dom/shared/__tests__/ReactMount-test.js +++ b/src/renderers/dom/shared/__tests__/ReactMount-test.js @@ -89,13 +89,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/shared/__tests__/ReactServerRendering-test.js b/src/renderers/dom/shared/__tests__/ReactServerRendering-test.js index 93f291c2b0783..889356a1f135b 100644 --- a/src/renderers/dom/shared/__tests__/ReactServerRendering-test.js +++ b/src/renderers/dom/shared/__tests__/ReactServerRendering-test.js @@ -490,32 +490,6 @@ describe('ReactDOMServer', () => { 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'); - ReactDOMServer.renderToString(); - jest.runOnlyPendingTimers(); - expectDev(console.error.calls.count()).toBe(1); - expectDev(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.\n\nPlease check the code for the Bar component.', - ); - var markup = ReactDOMServer.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/eventPlugins/__tests__/BeforeInputEventPlugin-test.js b/src/renderers/dom/shared/eventPlugins/__tests__/BeforeInputEventPlugin-test.js index cc99a00dbca33..5007116a6ea09 100644 --- a/src/renderers/dom/shared/eventPlugins/__tests__/BeforeInputEventPlugin-test.js +++ b/src/renderers/dom/shared/eventPlugins/__tests__/BeforeInputEventPlugin-test.js @@ -207,9 +207,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/shared/fiber/__tests__/ReactIncremental-test.js b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js index 96a3f032e5f9d..f0da503be5e12 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js @@ -873,15 +873,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 ( @@ -895,7 +893,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/fiber/__tests__/ReactIncrementalReflection-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalReflection-test.js index bae5b1e35fdb6..f19d1d3593e28 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncrementalReflection-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalReflection-test.js @@ -29,18 +29,23 @@ describe('ReactIncrementalReflection', () => { const instances = []; - const Component = React.createClass({ + 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() { instances.push(this); - ops.push('componentWillMount', this.isMounted()); - }, + ops.push('componentWillMount', this._isMounted()); + } componentDidMount() { - ops.push('componentDidMount', this.isMounted()); - }, + ops.push('componentDidMount', this._isMounted()); + } render() { return ; - }, - }); + } + } function Foo() { return ; @@ -53,7 +58,7 @@ describe('ReactIncrementalReflection', () => { expect(ops).toEqual(['componentWillMount', false]); - expect(instances[0].isMounted()).toBe(false); + expect(instances[0]._isMounted()).toBe(false); ops = []; @@ -62,7 +67,7 @@ describe('ReactIncrementalReflection', () => { expect(ops).toEqual(['componentDidMount', true]); - expect(instances[0].isMounted()).toBe(true); + expect(instances[0]._isMounted()).toBe(true); }); it('handles isMounted when an unmount is deferred', () => { @@ -70,18 +75,21 @@ describe('ReactIncrementalReflection', () => { const instances = []; - const Component = React.createClass({ + class Component extends React.Component { + _isMounted() { + return this.updater.isMounted(this); + } componentWillMount() { instances.push(this); - }, + } componentWillUnmount() { - ops.push('componentWillUnmount', this.isMounted()); - }, + ops.push('componentWillUnmount', this._isMounted()); + } render() { ops.push('Component'); return ; - }, - }); + } + } function Other() { ops.push('Other'); @@ -98,7 +106,7 @@ describe('ReactIncrementalReflection', () => { expect(ops).toEqual(['Component']); ops = []; - expect(instances[0].isMounted()).toBe(true); + expect(instances[0]._isMounted()).toBe(true); ReactNoop.render(); // Render part way through but don't yet commit the updates so it is not @@ -108,14 +116,14 @@ describe('ReactIncrementalReflection', () => { expect(ops).toEqual(['Other']); ops = []; - expect(instances[0].isMounted()).toBe(true); + expect(instances[0]._isMounted()).toBe(true); // Finish flushing the unmount. ReactNoop.flush(); expect(ops).toEqual(['componentWillUnmount', true]); - expect(instances[0].isMounted()).toBe(false); + expect(instances[0]._isMounted()).toBe(false); }); it('finds no node before insertion and correct node before deletion', () => { diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js index b55d7a3196267..69cfe35360115 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js @@ -74,22 +74,20 @@ describe('ReactIncrementalUpdates', () => { it('only drops updates with equal or lesser priority when replaceState is called', () => { let instance; let ops = []; - const Foo = React.createClass({ - getInitialState() { - return {}; - }, + class Foo extends React.Component { + state = {}; componentDidMount() { ops.push('componentDidMount'); - }, + } componentDidUpdate() { ops.push('componentDidUpdate'); - }, + } render() { ops.push('render'); instance = this; return
; - }, - }); + } + } ReactNoop.render(); ReactNoop.flush(); @@ -100,7 +98,7 @@ describe('ReactIncrementalUpdates', () => { instance.setState({a: 'a'}); instance.setState({b: 'b'}); }); - instance.replaceState({c: 'c'}); + instance.updater.enqueueReplaceState(instance, {c: 'c'}); instance.setState({d: 'd'}); ReactNoop.flushAnimationPri(); @@ -201,19 +199,17 @@ describe('ReactIncrementalUpdates', () => { it('can abort an update, schedule a replaceState, and resume', () => { let instance; let ops = []; - const Foo = React.createClass({ - getInitialState() { - return {}; - }, + class Foo extends React.Component { + state = {}; componentDidUpdate() { ops.push('componentDidUpdate'); - }, + } render() { ops.push('render'); instance = this; return ; - }, - }); + } + } ReactNoop.render(); ReactNoop.flush(); @@ -245,7 +241,9 @@ describe('ReactIncrementalUpdates', () => { instance.setState(createUpdate('f')); ReactNoop.performAnimationWork(() => { instance.setState(createUpdate('d')); - instance.replaceState(createUpdate('e')); + // No longer a public API, but we can test that it works internally by + // reaching into the updater. + instance.updater.enqueueReplaceState(instance, createUpdate('e')); }); instance.setState(createUpdate('g')); @@ -256,21 +254,21 @@ describe('ReactIncrementalUpdates', () => { it('passes accumulation of previous updates to replaceState updater function', () => { let instance; - const Foo = React.createClass({ - getInitialState() { - return {}; - }, + class Foo extends React.Component { + state = {}; render() { instance = this; return ; - }, - }); + } + } ReactNoop.render(); ReactNoop.flush(); instance.setState({a: 'a'}); instance.setState({b: 'b'}); - instance.replaceState(previousState => ({previousState})); + // No longer a public API, but we can test that it works internally by + // reaching into the updater. + instance.updater.enqueueReplaceState(instance, previousState => ({previousState})); ReactNoop.flush(); expect(instance.state).toEqual({previousState: {a: 'a', b: 'b'}}); }); diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js index a196a0b116570..68c489cfb8f3d 100644 --- a/src/test/__tests__/ReactTestUtils-test.js +++ b/src/test/__tests__/ReactTestUtils-test.js @@ -90,12 +90,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(); From 194b25f7099f2bdc85917e26a0a490f942f2553b Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 21 Mar 2017 18:39:18 -0700 Subject: [PATCH 15/43] Run prettier --- .../__tests__/ReactContextValidator-test.js | 1 - .../element/__tests__/ReactElement-test.js | 16 +++++++++++++--- .../element/__tests__/ReactElementClone-test.js | 13 +++++++------ .../__tests__/ReactElementValidator-test.js | 5 ++--- .../__tests__/ReactComponentLifeCycle-test.js | 4 ++-- .../ReactCompositeComponentState-test.js | 4 ++-- .../__tests__/ReactStatelessComponent-test.js | 4 +++- .../__tests__/ReactIncrementalUpdates-test.js | 4 +++- 8 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js index c05c6a305ca7f..84a220877f8cb 100644 --- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js +++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js @@ -156,7 +156,6 @@ describe('ReactContextValidator', () => { foo: React.PropTypes.string, }; - var container = document.createElement('div'); ReactDOM.render(, container); ReactDOM.render(, container); diff --git a/src/isomorphic/classic/element/__tests__/ReactElement-test.js b/src/isomorphic/classic/element/__tests__/ReactElement-test.js index d03f176ba6ba0..30a74615feb3c 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElement-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElement-test.js @@ -497,7 +497,7 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => { ); } }; - instance = ReactTestUtils.renderIntoDocument(); + instance = ReactTestUtils.renderIntoDocument(); }); it('should scry children but cannot', () => { @@ -526,7 +526,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => { var childFactory = React.createFactory(Child); class Parent extends React.Component { render() { - return React.DOM.div({}, childFactory({ ref: 'child', foo: 'foo value' }, 'children value')); + return React.DOM.div( + {}, + childFactory({ref: 'child', foo: 'foo value'}, 'children value'), + ); } } factory = React.createFactory(Parent); @@ -558,7 +561,14 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => { beforeEach(() => { class Parent extends React.Component { render() { - return React.DOM.div({}, React.createElement(Child, { ref: 'child', foo: 'foo value' }, 'children value')); + return React.DOM.div( + {}, + React.createElement( + Child, + {ref: 'child', foo: 'foo value'}, + 'children value', + ), + ); } } factory = React.createFactory(Parent); diff --git a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js index f1baac684c376..827509b196ea4 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js @@ -177,8 +177,10 @@ describe('ReactElementClone', () => { it('should support keys and refs', () => { class Parent extends React.Component { render() { - var clone = - React.cloneElement(this.props.children, {key: 'xyz', ref: 'xyz'}); + var clone = React.cloneElement(this.props.children, { + key: 'xyz', + ref: 'xyz', + }); expect(clone.key).toBe('xyz'); expect(clone.ref).toBe('xyz'); return
{clone}
; @@ -300,10 +302,9 @@ describe('ReactElementClone', () => { } class GrandParent extends React.Component { render() { - return React.createElement( - Parent, - { child: React.createElement(Component, {color: 'red'}) } - ); + return React.createElement(Parent, { + child: React.createElement(Component, {color: 'red'}), + }); } } ReactTestUtils.renderIntoDocument(React.createElement(GrandParent)); diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js index 8b88e5a44dcd6..ada2bb20fa7ec 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js @@ -64,7 +64,7 @@ describe('ReactElementValidator', () => { class ComponentWrapper extends React.Component { render() { - return InnerComponent({childSet: [Component(), Component()] }); + return InnerComponent({childSet: [Component(), Component()]}); } } @@ -84,7 +84,7 @@ describe('ReactElementValidator', () => { function Anonymous() { return
; } - Object.defineProperty(Anonymous, 'name', { value: undefined }); + Object.defineProperty(Anonymous, 'name', {value: undefined}); var divs = [
,
]; ReactTestUtils.renderIntoDocument({divs}); @@ -418,7 +418,6 @@ describe('ReactElementValidator', () => { class Component extends React.Component { render() { return React.createElement('span', null, this.props.myProp.value); - } } Component.propTypes = { diff --git a/src/renderers/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/__tests__/ReactComponentLifeCycle-test.js index ab13a65b44c32..b9231571bb733 100644 --- a/src/renderers/__tests__/ReactComponentLifeCycle-test.js +++ b/src/renderers/__tests__/ReactComponentLifeCycle-test.js @@ -239,7 +239,7 @@ describe('ReactComponentLifeCycle', () => { } render() { expect(this._isMounted()).toBeFalsy(); - return
; + return
; } } @@ -288,7 +288,7 @@ describe('ReactComponentLifeCycle', () => { it('isMounted should return false when unmounted', () => { class Component extends React.Component { render() { - return
; + return
; } } diff --git a/src/renderers/__tests__/ReactCompositeComponentState-test.js b/src/renderers/__tests__/ReactCompositeComponentState-test.js index ca88e476736e8..958d40692daac 100644 --- a/src/renderers/__tests__/ReactCompositeComponentState-test.js +++ b/src/renderers/__tests__/ReactCompositeComponentState-test.js @@ -33,11 +33,11 @@ describe('ReactCompositeComponent-state', () => { peekAtState = (from, state = this.state, props = this.props) => { props.stateListener(from, state && state.color); - } + }; peekAtCallback = from => { return () => this.peekAtState(from); - } + }; setFavoriteColor(nextColor) { this.setState( diff --git a/src/renderers/__tests__/ReactStatelessComponent-test.js b/src/renderers/__tests__/ReactStatelessComponent-test.js index b1cc7ba9d0838..3f11bf438e15e 100644 --- a/src/renderers/__tests__/ReactStatelessComponent-test.js +++ b/src/renderers/__tests__/ReactStatelessComponent-test.js @@ -280,7 +280,9 @@ describe('ReactStatelessComponent', () => { }); } } - Object.defineProperty(AnonymousParentNotUsingJSX, 'name', {value: undefined}); + Object.defineProperty(AnonymousParentNotUsingJSX, 'name', { + value: undefined, + }); const instance2 = ReactTestUtils.renderIntoDocument( , diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js index 69cfe35360115..2483732fc1465 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js @@ -268,7 +268,9 @@ describe('ReactIncrementalUpdates', () => { instance.setState({b: 'b'}); // No longer a public API, but we can test that it works internally by // reaching into the updater. - instance.updater.enqueueReplaceState(instance, previousState => ({previousState})); + instance.updater.enqueueReplaceState(instance, previousState => ({ + previousState, + })); ReactNoop.flush(); expect(instance.state).toEqual({previousState: {a: 'a', b: 'b'}}); }); From 646e7863348a427e1ed9163a9a96fa759112f102 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 21 Mar 2017 19:09:32 -0700 Subject: [PATCH 16/43] Warn once when attempting to access React.createClass Should still be undefined. --- scripts/fiber/tests-passing.txt | 1 + src/isomorphic/React.js | 46 +++++++++++++++++--------- src/isomorphic/__tests__/React-test.js | 14 ++++++++ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index cf40f4bb6cd81..ca26fd1a00928 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -44,6 +44,7 @@ scripts/shared/__tests__/evalToString-test.js src/isomorphic/__tests__/React-test.js * should log a deprecation warning once when using React.createMixin +* should warn once when attempting to access React.createClass src/isomorphic/children/__tests__/ReactChildren-test.js * should support identity for simple diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index a37649a3197b6..402f02c7c88db 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -19,7 +19,6 @@ var ReactPropTypes = require('ReactPropTypes'); var ReactVersion = require('ReactVersion'); var onlyChild = require('onlyChild'); -var warning = require('fbjs/lib/warning'); var checkPropTypes = require('checkPropTypes'); var createElement = ReactElement.createElement; @@ -27,6 +26,8 @@ var createFactory = ReactElement.createFactory; var cloneElement = ReactElement.cloneElement; if (__DEV__) { + var warning = require('fbjs/lib/warning'); + var canDefineProperty = require('canDefineProperty'); var ReactElementValidator = require('ReactElementValidator'); createElement = ReactElementValidator.createElement; createFactory = ReactElementValidator.createFactory; @@ -37,20 +38,6 @@ var createMixin = function(mixin) { return mixin; }; -if (__DEV__) { - var warnedForCreateMixin = false; - - createMixin = function(mixin) { - warning( - warnedForCreateMixin, - 'React.createMixin is deprecated and should not be used. You ' + - 'can use this mixin directly instead.', - ); - warnedForCreateMixin = true; - return mixin; - }; -} - var React = { // Modern @@ -94,6 +81,35 @@ if (__DEV__) { ReactComponentTreeHook: require('ReactComponentTreeHook'), ReactDebugCurrentFrame: require('ReactDebugCurrentFrame'), }); + + let warnedForCreateMixin = false; + let warnedForCreateClass = false; + + React.createMixin = function(mixin) { + warning( + warnedForCreateMixin, + 'React.createMixin is deprecated and should not be used. You ' + + 'can use this mixin directly instead.', + ); + warnedForCreateMixin = true; + return mixin; + }; + + if (canDefineProperty) { + Object.defineProperty(React, 'createClass', { + get: function() { + warning( + warnedForCreateClass, + 'React.createClass is no longer supported. Use a plain JavaScript ' + + "class instead. If you're not yet ready to migrate, " + + 'react-create-class is available on npm as a temporary, ' + + 'drop-in replacement.', + ); + warnedForCreateClass = true; + return undefined; + }, + }); + } } module.exports = React; diff --git a/src/isomorphic/__tests__/React-test.js b/src/isomorphic/__tests__/React-test.js index ec007f16a32b5..4b9c4960abca8 100644 --- a/src/isomorphic/__tests__/React-test.js +++ b/src/isomorphic/__tests__/React-test.js @@ -27,4 +27,18 @@ describe('React', () => { 'React.createMixin is deprecated and should not be used', ); }); + + it('should warn once when attempting to access React.createClass', () => { + spyOn(console, 'error'); + let createClass = React.createClass; + createClass = React.createClass; + expect(createClass).toBe(undefined); + expectDev(console.error.calls.count()).toBe(1); + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'React.createClass is no longer supported. Use a plain ' + + "JavaScript class instead. If you're not yet ready to migrate, " + + 'react-create-class is available on npm as a temporary, ' + + 'drop-in replacement.', + ); + }); }); From 6b539f280d8b0ec4874671bae9c6bed80b788006 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Mon, 27 Mar 2017 16:33:08 -0700 Subject: [PATCH 17/43] Convert createClass caller This snuck in after rebasing --- .../wrappers/__tests__/ReactDOMInput-test.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js index 62df49a453262..102acc241800c 100644 --- a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js @@ -1119,22 +1119,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() { From ce489262a1ee34340440e55a0b99ea6918e19e7a Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Mon, 27 Mar 2017 16:34:23 -0700 Subject: [PATCH 18/43] Add react-create-class integration tests These are mostly copied from the old ReactClass-test module. --- scripts/fiber/tests-passing.txt | 18 + .../react-create-class-integration-test.js | 436 ++++++++++++++++++ yarn.lock | 6 + 3 files changed, 460 insertions(+) create mode 100644 src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index ca26fd1a00928..7cf4d1ff0bff4 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -90,6 +90,24 @@ src/isomorphic/classic/__tests__/ReactContextValidator-test.js * should warn (but not error) if getChildContext method is missing * should pass parent context if getChildContext method is missing +src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js +* should throw when `render` is not specified +* should copy prop types onto the Constructor +* should warn on invalid prop types +* should warn on invalid context types +* should throw on invalid child context types +* should warn when mispelling shouldComponentUpdate +* should warn when mispelling componentWillReceiveProps +* should throw if a reserved property is in statics +* should support statics +* should work with object getInitialState() return values +* renders based on context getInitialState +* should throw with non-object getInitialState() return values +* should work with a null getInitialState() return value +* should throw when using legacy factories +* replaceState and callback works +* isMounted works + src/isomorphic/classic/element/__tests__/ReactElement-test.js * uses the fallback value when in an environment without Symbol * returns a complete element according to spec diff --git a/src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js b/src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js new file mode 100644 index 0000000000000..cbcb1a2a43cfb --- /dev/null +++ b/src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js @@ -0,0 +1,436 @@ +/** + * 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 ReactCreateClass; + +describe('react-create-class-integration', () => { + beforeEach(() => { + React = require('React'); + ReactDOM = require('ReactDOM'); + ReactTestUtils = require('ReactTestUtils'); + var ReactCreateClassFactory = require('react-create-class/factory'); + ReactCreateClass = ReactCreateClassFactory( + React.Component, + React.isValidElement, + require('ReactNoopUpdateQueue'), + ); + }); + + it('should throw when `render` is not specified', () => { + expect(function() { + ReactCreateClass({}); + }).toThrowError( + 'createClass(...): Class specification must implement a `render` method.', + ); + }); + + // TODO: Update babel-plugin-transform-react-display-name + xit('should copy `displayName` onto the Constructor', () => { + var TestComponent = ReactCreateClass({ + render: function() { + return
; + }, + }); + + expect(TestComponent.displayName).toBe('TestComponent'); + }); + + it('should copy prop types onto the Constructor', () => { + var propValidator = jest.fn(); + var TestComponent = ReactCreateClass({ + 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'); + ReactCreateClass({ + 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'); + ReactCreateClass({ + 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'); + ReactCreateClass({ + 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'); + + ReactCreateClass({ + 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.', + ); + + ReactCreateClass({ + 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'); + ReactCreateClass({ + 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() { + ReactCreateClass({ + 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'); + ReactCreateClass({ + mixins: [{}], + propTypes: { + foo: React.PropTypes.string, + }, + contextTypes: { + foo: React.PropTypes.string, + }, + childContextTypes: { + foo: React.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 = ReactCreateClass({ + 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 = ReactCreateClass({ + 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 = ReactCreateClass({ + contextTypes: { + className: React.PropTypes.string, + }, + getInitialState() { + return {className: this.context.className}; + }, + render() { + return ; + }, + }); + + var Outer = ReactCreateClass({ + childContextTypes: { + className: React.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 = ReactCreateClass({ + 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 = ReactCreateClass({ + getInitialState: function() { + return null; + }, + render: function() { + return ; + }, + }); + expect(() => + ReactTestUtils.renderIntoDocument()).not.toThrow(); + }); + + it('should throw when using legacy factories', () => { + spyOn(console, 'error'); + var Component = ReactCreateClass({ + 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', + ); + }); + + it('replaceState and callback works', () => { + var ops = []; + var Component = ReactCreateClass({ + getInitialState() { + return {step: 0}; + }, + render() { + ops.push('Render: ' + this.state.step); + return
; + }, + }); + + var instance = ReactTestUtils.renderIntoDocument(); + instance.replaceState({step: 1}, () => { + ops.push('Callback: ' + instance.state.step); + }); + expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']); + }); + + it('isMounted works', () => { + spyOn(console, 'error'); + + var ops = []; + var instance; + var Component = ReactCreateClass({ + displayName: 'MyComponent', + log(name) { + ops.push(`${name}: ${this.isMounted()}`); + }, + getInitialState() { + this.log('getInitialState'); + return {}; + }, + componentWillMount() { + this.log('componentWillMount'); + }, + componentDidMount() { + this.log('componentDidMount'); + }, + componentWillUpdate() { + this.log('componentWillUpdate'); + }, + componentDidUpdate() { + this.log('componentDidUpdate'); + }, + componentWillUnmount() { + this.log('componentWillUnmount'); + }, + render() { + instance = this; + this.log('render'); + return
; + }, + }); + + var container = document.createElement('div'); + ReactDOM.render(, container); + ReactDOM.render(, container); + ReactDOM.unmountComponentAtNode(container); + instance.log('after unmount'); + expect(ops).toEqual([ + 'getInitialState: false', + 'componentWillMount: false', + 'render: false', + 'componentDidMount: true', + 'componentWillUpdate: true', + 'render: true', + 'componentDidUpdate: true', + 'componentWillUnmount: false', + 'after unmount: false', + ]); + + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toEqual( + 'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' + + 'clean up subscriptions and pending requests in componentWillUnmount ' + + 'to prevent memory leaks.', + ); + }); +}); diff --git a/yarn.lock b/yarn.lock index 0314dfbc94221..a48ed072bcdf5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4004,6 +4004,12 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-create-class@15.5.0-alpha.7: + version "15.5.0-alpha.7" + resolved "https://registry.yarnpkg.com/react-create-class/-/react-create-class-15.5.0-alpha.7.tgz#a2bf8846ab0f0e86799e8a2c2346d7a87941a350" + dependencies: + fbjs "^0.8.9" + 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" From 957fbc92b123030c389bf8b4b874522bdf2db72c Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Fri, 7 Apr 2017 15:17:15 -0700 Subject: [PATCH 19/43] react-create-class -> create-react-class --- package.json | 1 + scripts/fiber/tests-passing.txt | 2 +- src/isomorphic/React.js | 2 +- src/isomorphic/__tests__/React-test.js | 2 +- ...=> create-react-class-integration-test.js} | 57 ++++++++----------- yarn.lock | 12 ++-- 6 files changed, 33 insertions(+), 43 deletions(-) rename src/isomorphic/classic/class/__tests__/{react-create-class-integration-test.js => create-react-class-integration-test.js} (91%) diff --git a/package.json b/package.json index 80b6c1d734d89..35589b84c6e68 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "coffee-script": "^1.8.0", "core-js": "^2.2.1", "coveralls": "^2.11.6", + "create-react-class": "^15.5.0", "del": "^2.0.2", "derequire": "^2.0.3", "escape-string-regexp": "^1.0.5", diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 7cf4d1ff0bff4..89dc4c89febb1 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -90,7 +90,7 @@ src/isomorphic/classic/__tests__/ReactContextValidator-test.js * should warn (but not error) if getChildContext method is missing * should pass parent context if getChildContext method is missing -src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js +src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js * should throw when `render` is not specified * should copy prop types onto the Constructor * should warn on invalid prop types diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index 402f02c7c88db..ccc351225edb8 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -102,7 +102,7 @@ if (__DEV__) { warnedForCreateClass, 'React.createClass is no longer supported. Use a plain JavaScript ' + "class instead. If you're not yet ready to migrate, " + - 'react-create-class is available on npm as a temporary, ' + + 'create-react-class is available on npm as a temporary, ' + 'drop-in replacement.', ); warnedForCreateClass = true; diff --git a/src/isomorphic/__tests__/React-test.js b/src/isomorphic/__tests__/React-test.js index 4b9c4960abca8..f2ea926dd9a08 100644 --- a/src/isomorphic/__tests__/React-test.js +++ b/src/isomorphic/__tests__/React-test.js @@ -37,7 +37,7 @@ describe('React', () => { expectDev(console.error.calls.argsFor(0)[0]).toContain( 'React.createClass is no longer supported. Use a plain ' + "JavaScript class instead. If you're not yet ready to migrate, " + - 'react-create-class is available on npm as a temporary, ' + + 'create-react-class is available on npm as a temporary, ' + 'drop-in replacement.', ); }); diff --git a/src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js similarity index 91% rename from src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js rename to src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js index cbcb1a2a43cfb..3eddc9730524c 100644 --- a/src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js +++ b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js @@ -14,15 +14,15 @@ var React; var ReactDOM; var ReactTestUtils; -var ReactCreateClass; +var createReactClass; -describe('react-create-class-integration', () => { +describe('create-react-class-integration', () => { beforeEach(() => { React = require('React'); ReactDOM = require('ReactDOM'); ReactTestUtils = require('ReactTestUtils'); - var ReactCreateClassFactory = require('react-create-class/factory'); - ReactCreateClass = ReactCreateClassFactory( + var createReactClassFactory = require('create-react-class/factory'); + createReactClass = createReactClassFactory( React.Component, React.isValidElement, require('ReactNoopUpdateQueue'), @@ -31,26 +31,15 @@ describe('react-create-class-integration', () => { it('should throw when `render` is not specified', () => { expect(function() { - ReactCreateClass({}); + createReactClass({}); }).toThrowError( 'createClass(...): Class specification must implement a `render` method.', ); }); - // TODO: Update babel-plugin-transform-react-display-name - xit('should copy `displayName` onto the Constructor', () => { - var TestComponent = ReactCreateClass({ - render: function() { - return
; - }, - }); - - expect(TestComponent.displayName).toBe('TestComponent'); - }); - it('should copy prop types onto the Constructor', () => { var propValidator = jest.fn(); - var TestComponent = ReactCreateClass({ + var TestComponent = createReactClass({ propTypes: { value: propValidator, }, @@ -65,7 +54,7 @@ describe('react-create-class-integration', () => { it('should warn on invalid prop types', () => { spyOn(console, 'error'); - ReactCreateClass({ + createReactClass({ displayName: 'Component', propTypes: { prop: null, @@ -83,7 +72,7 @@ describe('react-create-class-integration', () => { it('should warn on invalid context types', () => { spyOn(console, 'error'); - ReactCreateClass({ + createReactClass({ displayName: 'Component', contextTypes: { prop: null, @@ -101,7 +90,7 @@ describe('react-create-class-integration', () => { it('should throw on invalid child context types', () => { spyOn(console, 'error'); - ReactCreateClass({ + createReactClass({ displayName: 'Component', childContextTypes: { prop: null, @@ -120,7 +109,7 @@ describe('react-create-class-integration', () => { it('should warn when mispelling shouldComponentUpdate', () => { spyOn(console, 'error'); - ReactCreateClass({ + createReactClass({ componentShouldUpdate: function() { return false; }, @@ -135,7 +124,7 @@ describe('react-create-class-integration', () => { 'because the function is expected to return a value.', ); - ReactCreateClass({ + createReactClass({ displayName: 'NamedComponent', componentShouldUpdate: function() { return false; @@ -154,7 +143,7 @@ describe('react-create-class-integration', () => { it('should warn when mispelling componentWillReceiveProps', () => { spyOn(console, 'error'); - ReactCreateClass({ + createReactClass({ componentWillRecieveProps: function() { return false; }, @@ -171,7 +160,7 @@ describe('react-create-class-integration', () => { it('should throw if a reserved property is in statics', () => { expect(function() { - ReactCreateClass({ + createReactClass({ statics: { getDefaultProps: function() { return { @@ -196,7 +185,7 @@ describe('react-create-class-integration', () => { xit('should warn when using deprecated non-static spec keys', () => { spyOn(console, 'error'); - ReactCreateClass({ + createReactClass({ mixins: [{}], propTypes: { foo: React.PropTypes.string, @@ -231,7 +220,7 @@ describe('react-create-class-integration', () => { }); it('should support statics', () => { - var Component = ReactCreateClass({ + var Component = createReactClass({ statics: { abc: 'def', def: 0, @@ -261,7 +250,7 @@ describe('react-create-class-integration', () => { }); it('should work with object getInitialState() return values', () => { - var Component = ReactCreateClass({ + var Component = createReactClass({ getInitialState: function() { return { occupation: 'clown', @@ -277,7 +266,7 @@ describe('react-create-class-integration', () => { }); it('renders based on context getInitialState', () => { - var Foo = ReactCreateClass({ + var Foo = createReactClass({ contextTypes: { className: React.PropTypes.string, }, @@ -289,7 +278,7 @@ describe('react-create-class-integration', () => { }, }); - var Outer = ReactCreateClass({ + var Outer = createReactClass({ childContextTypes: { className: React.PropTypes.string, }, @@ -308,7 +297,7 @@ describe('react-create-class-integration', () => { it('should throw with non-object getInitialState() return values', () => { [['an array'], 'a string', 1234].forEach(function(state) { - var Component = ReactCreateClass({ + var Component = createReactClass({ getInitialState: function() { return state; }, @@ -326,7 +315,7 @@ describe('react-create-class-integration', () => { }); it('should work with a null getInitialState() return value', () => { - var Component = ReactCreateClass({ + var Component = createReactClass({ getInitialState: function() { return null; }, @@ -340,7 +329,7 @@ describe('react-create-class-integration', () => { it('should throw when using legacy factories', () => { spyOn(console, 'error'); - var Component = ReactCreateClass({ + var Component = createReactClass({ render() { return
; }, @@ -356,7 +345,7 @@ describe('react-create-class-integration', () => { it('replaceState and callback works', () => { var ops = []; - var Component = ReactCreateClass({ + var Component = createReactClass({ getInitialState() { return {step: 0}; }, @@ -378,7 +367,7 @@ describe('react-create-class-integration', () => { var ops = []; var instance; - var Component = ReactCreateClass({ + var Component = createReactClass({ displayName: 'MyComponent', log(name) { ops.push(`${name}: ${this.isMounted()}`); diff --git a/yarn.lock b/yarn.lock index a48ed072bcdf5..681679cb60642 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1438,6 +1438,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2: create-hash "^1.1.0" inherits "^2.0.1" +create-react-class@^15.5.0: + version "15.5.0" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.0.tgz#7508ffcad56a0804fb244d6ff70b07648abfe5fb" + dependencies: + fbjs "^0.8.9" + cross-spawn-async@^2.2.2: version "2.2.5" resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" @@ -4004,12 +4010,6 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-create-class@15.5.0-alpha.7: - version "15.5.0-alpha.7" - resolved "https://registry.yarnpkg.com/react-create-class/-/react-create-class-15.5.0-alpha.7.tgz#a2bf8846ab0f0e86799e8a2c2346d7a87941a350" - dependencies: - fbjs "^0.8.9" - 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" From b1a06bd9456ea81184be0c15108cd3a3ed18084f Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Tue, 11 Apr 2017 13:58:14 -0700 Subject: [PATCH 20/43] Fix ignore patterns in package.json (#9409) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 35589b84c6e68..c8cf86911ae0a 100644 --- a/package.json +++ b/package.json @@ -110,8 +110,8 @@ "jest": { "modulePathIgnorePatterns": [ "/.module-cache/", - "/react/build/", - "/react/scripts/rollup/shims/" + "/build/", + "/scripts/rollup/shims/" ], "rootDir": "", "transform": { From cec9b074024b8f1c897a22f9b12ec9a0301967b3 Mon Sep 17 00:00:00 2001 From: Denis Pismenny Date: Wed, 12 Apr 2017 00:03:53 +0300 Subject: [PATCH 21/43] Fix minor typo in lifting-state-up.md (#9408) --- docs/docs/lifting-state-up.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/lifting-state-up.md b/docs/docs/lifting-state-up.md index 60931231cbc23..17b4406720518 100644 --- a/docs/docs/lifting-state-up.md +++ b/docs/docs/lifting-state-up.md @@ -302,7 +302,7 @@ Let's recap what happens when you edit an input: * React calls the function specified as `onChange` on the DOM ``. In our case, this is the `handleChange` method in `TemperatureInput` component. * The `handleChange` method in the `TemperatureInput` component calls `this.props.onTemperatureChange()` with the new desired value. Its props, including `onTemperatureChange`, were provided by its parent component, the `Calculator`. -* When it previously rendered, the `Calculator` has specified that `onTemperatureChange` of the Celsius `TemperatureInput` is the `Calculator`'s `handleCelsiusChange` method, and `onTemperatureChange` of the Fahrenheit `TemperatureInput` is the `Calculator`'s `handleFahrehnheitChange` method. So either of these two `Calculator` methods gets called depending on which input we edited. +* When it previously rendered, the `Calculator` has specified that `onTemperatureChange` of the Celsius `TemperatureInput` is the `Calculator`'s `handleCelsiusChange` method, and `onTemperatureChange` of the Fahrenheit `TemperatureInput` is the `Calculator`'s `handleFahrenheitChange` method. So either of these two `Calculator` methods gets called depending on which input we edited. * Inside these methods, the `Calculator` component asks React to re-render itself by calling `this.setState()` with the new input value and the current scale of the input we just edited. * React calls the `Calculator` component's `render` method to learn what the UI should look like. The values of both inputs are recomputed based on the current temperature and the active scale. The temperature conversion is performed here. * React calls the `render` methods of the individual `TemperatureInput` components with their new props specified by the `Calculator`. It learns what their UI should look like. From aa1f8687d7c93a00c07d63237bcd54b23b4f50af Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 11 Apr 2017 22:02:43 +0100 Subject: [PATCH 22/43] Use caret range in blog instructions The release was a bit broken. --- docs/_posts/2017-04-07-react-v15.5.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_posts/2017-04-07-react-v15.5.0.md b/docs/_posts/2017-04-07-react-v15.5.0.md index 050c304442c4d..7c38475c1a483 100644 --- a/docs/_posts/2017-04-07-react-v15.5.0.md +++ b/docs/_posts/2017-04-07-react-v15.5.0.md @@ -164,13 +164,13 @@ We recommend using [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) To install React with Yarn, run: ```bash -yarn add react@15.5.0 react-dom@15.5.0 +yarn add react@^15.5.0 react-dom@^15.5.0 ``` To install React with npm, run: ```bash -npm install --save react@15.5.0 react-dom@15.5.0 +npm install --save react@^15.5.0 react-dom@^15.5.0 ``` We recommend using a bundler like [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time. From 2beec2f308e27dbe902a8d68e1fc9f3d70ee9372 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 11 Apr 2017 14:28:03 -0700 Subject: [PATCH 23/43] createClass + PropTypes + checkPropTypes warnings (#9399) (Temporarily) re-adds getters with deprecation warnings for React.PropTypes, React.checkPropTypes, and React.createClass. * 08bd020: Replace all references to React.PropTypes with prop-types to avoid triggering our own warning message. * ef5b5c6: Removed several references to React.createClass that appeared after rebasing this branch. (reviewed by @flarnie) * 524ce20: Added getters for createClass and PropTypes to the main React isomorphic object, behind one-time warning messages. (reviewed by @spicyj) * db48f54: Fixed Rollup bundles to inline 'prop-types' and 'create-react-class' for UMD builds only. (reviewed by @spicyj, @trueadm ) * cf49cfd: Updated tests-passing.txt to remove tests that were deleted in this branch. * d34109a: Responses to PR feedback from @spicyj. (Added package.json dependencies to packages/react and packages/react-dom. Renamed a var. Expanded on an inline comment.) * 488c8d2: Added warning for moved package to React.checkPropTypes accessor too and updated build script. * 83bcb29: Wordsmithing for deprecation notices (added fb.me links). * afdc9d2: Tweaked legacy module inlining to remove order-of-deps constraint * d1348b9: Removed $FlowFixMe. * 7dbc3e7: More wordsmithing of deprecation notices based on Dan's feedback. --- fixtures/art/VectorWidget.js | 36 +- fixtures/dom/package.json | 1 + fixtures/dom/public/index.html | 1 + fixtures/dom/src/components/App.js | 20 +- fixtures/dom/src/components/Fixture.js | 3 +- fixtures/dom/src/components/FixtureSet.js | 5 +- fixtures/dom/src/components/Header.js | 19 +- fixtures/dom/src/components/TestCase.js | 9 +- .../src/components/fixtures/buttons/index.js | 2 +- fixtures/dom/src/components/fixtures/index.js | 46 +- .../fixtures/number-inputs/NumberTestCase.js | 14 +- .../fixtures/number-inputs/index.js | 314 +++++----- .../password-inputs/PasswordTestCase.js | 14 +- .../fixtures/password-inputs/index.js | 44 +- .../components/fixtures/range-inputs/index.js | 14 +- .../src/components/fixtures/selects/index.js | 14 +- .../components/fixtures/text-inputs/index.js | 22 +- .../components/fixtures/textareas/index.js | 14 +- fixtures/dom/src/components/propTypes.js | 5 +- fixtures/dom/yarn.lock | 6 + package.json | 3 +- packages/react-dom/package.json | 3 +- packages/react/package.json | 4 +- scripts/fiber/tests-passing.txt | 15 +- scripts/jest/ts-preprocessor.js | 2 +- scripts/rollup/bundles.js | 29 +- scripts/rollup/modules.js | 34 +- scripts/rollup/results.json | 128 ++-- src/isomorphic/React.js | 44 +- src/isomorphic/__tests__/React-test.js | 40 +- .../__tests__/ReactContextValidator-test.js | 42 +- .../create-react-class-integration-test.js | 16 +- src/isomorphic/classic/class/createClass.js | 19 + .../__tests__/ReactElementClone-test.js | 8 +- .../__tests__/ReactElementValidator-test.js | 24 +- .../classic/types/ReactPropTypes.js | 547 +----------------- .../ReactPropTypesProduction-test.js | 219 ------- .../classic/types/checkPropTypes.js | 82 +-- src/isomorphic/modern/class/PropTypes.d.ts | 19 + .../ReactCoffeeScriptClass-test.coffee | 14 +- .../class/__tests__/ReactES6Class-test.js | 14 +- .../__tests__/ReactTypeScriptClass-test.ts | 14 +- .../ReactJSXElementValidator-test.js | 8 +- .../__tests__/ReactComponentLifeCycle-test.js | 6 +- .../ReactComponentTreeHook-test.native.js | 4 +- .../__tests__/ReactErrorBoundaries-test.js | 6 +- .../__tests__/ReactStatelessComponent-test.js | 14 +- .../dom/fiber/__tests__/ReactDOMFiber-test.js | 21 +- .../ReactDOMServerIntegration-test.js | 30 +- .../renderSubtreeIntoContainer-test.js | 33 +- .../utils/ReactControlledValuePropTypes.js | 4 +- .../__tests__/ReactNativeEvents-test.js | 4 +- .../shared/fiber/ReactFiberContext.js | 8 +- .../fiber/__tests__/ReactIncremental-test.js | 34 +- .../ReactIncrementalErrorHandling-test.js | 8 +- .../__tests__/ReactIncrementalPerf-test.js | 4 +- .../reconciler/ReactCompositeComponent.js | 3 +- src/test/__tests__/ReactTestUtils-test.js | 8 +- yarn.lock | 13 +- 59 files changed, 734 insertions(+), 1397 deletions(-) create mode 100644 src/isomorphic/classic/class/createClass.js delete mode 100644 src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js create mode 100644 src/isomorphic/modern/class/PropTypes.d.ts diff --git a/fixtures/art/VectorWidget.js b/fixtures/art/VectorWidget.js index dda64bee188db..da5cde9e4be3f 100644 --- a/fixtures/art/VectorWidget.js +++ b/fixtures/art/VectorWidget.js @@ -24,13 +24,11 @@ var BASE_VEL = 0.15; /** * An animated SVG component. */ -var VectorWidget = React.createClass({ +class VectorWidget extends React.Component { /** * Initialize state members. */ - getInitialState: function() { - return {degrees: 0, velocity: 0, drag: MOUSE_UP_DRAG}; - }, + state = {degrees: 0, velocity: 0, drag: MOUSE_UP_DRAG}; /** * When the component is mounted into the document - this is similar to a @@ -39,40 +37,40 @@ var VectorWidget = React.createClass({ * method. Binding of `this.onTick` is not needed because all React methods * are automatically bound before being mounted. */ - componentDidMount: function() { + componentDidMount() { this._interval = window.setInterval(this.onTick, 20); - }, + } - componentWillUnmount: function() { + componentWillUnmount() { window.clearInterval(this._interval); - }, + } - onTick: function() { + onTick = () => { var nextDegrees = this.state.degrees + BASE_VEL + this.state.velocity; var nextVelocity = this.state.velocity * this.state.drag; this.setState({degrees: nextDegrees, velocity: nextVelocity}); - }, + }; /** * When mousing down, we increase the friction down the velocity. */ - handleMouseDown: function() { + handleMouseDown = () => { this.setState({drag: MOUSE_DOWN_DRAG}); - }, + }; /** * Cause the rotation to "spring". */ - handleMouseUp: function() { + handleMouseUp = () => { var nextVelocity = Math.min(this.state.velocity + CLICK_ACCEL, MAX_VEL); this.setState({velocity: nextVelocity, drag: MOUSE_UP_DRAG}); - }, + }; /** * This is the "main" method for any component. The React API allows you to * describe the structure of your UI component at *any* point in time. */ - render: function() { + render() { return ( ); - }, + } /** * Better SVG support for React coming soon. */ - renderGraphic: function(rotation) { + renderGraphic = (rotation) => { return ( ); - } -}); + }; +} var BORDER_PATH = "M3.00191459,4 C1.34400294,4 0,5.34785514 0,7.00550479 L0,220.994495 C0,222.65439 1.34239483,224 3.00191459,224 L276.998085,224 C278.655997,224 280,222.652145 280,220.994495 L280,7.00550479 C280,5.34561033 278.657605,4 276.998085,4 L3.00191459,4 Z M3.00191459,4"; var BG_PATH = "M3.00191459,1 C1.34400294,1 0,2.34785514 0,4.00550479 L0,217.994495 C0,219.65439 1.34239483,221 3.00191459,221 L276.998085,221 C278.655997,221 280,219.652145 280,217.994495 L280,4.00550479 C280,2.34561033 278.657605,1 276.998085,1 L3.00191459,1 Z M3.00191459,1"; diff --git a/fixtures/dom/package.json b/fixtures/dom/package.json index 07a70c4dc1d74..214de66fb73a6 100644 --- a/fixtures/dom/package.json +++ b/fixtures/dom/package.json @@ -8,6 +8,7 @@ "dependencies": { "classnames": "^2.2.5", "query-string": "^4.2.3", + "prop-types": "^15.5.6", "react": "^15.4.1", "react-dom": "^15.4.1", "semver": "^5.3.0" diff --git a/fixtures/dom/public/index.html b/fixtures/dom/public/index.html index a131a92882520..ed1922517a1b9 100644 --- a/fixtures/dom/public/index.html +++ b/fixtures/dom/public/index.html @@ -14,6 +14,7 @@ Learn how to configure a non-root public URL by running `npm run build`. --> React App + diff --git a/fixtures/dom/src/components/App.js b/fixtures/dom/src/components/App.js index 92550c638cff9..a22b1d918c4f6 100644 --- a/fixtures/dom/src/components/App.js +++ b/fixtures/dom/src/components/App.js @@ -4,17 +4,15 @@ import Fixtures from './fixtures'; import '../style.css'; -const App = React.createClass({ - render() { - return ( -
-
-
- -
+function App () { + return ( +
+
+
+
- ); - }, -}); +
+ ); +} export default App; diff --git a/fixtures/dom/src/components/Fixture.js b/fixtures/dom/src/components/Fixture.js index 1f6ef9ba09997..6074fa7d44c4e 100644 --- a/fixtures/dom/src/components/Fixture.js +++ b/fixtures/dom/src/components/Fixture.js @@ -1,7 +1,8 @@ +const PropTypes = window.PropTypes; const React = window.React; const propTypes = { - children: React.PropTypes.node.isRequired, + children: PropTypes.node.isRequired, }; class Fixture extends React.Component { diff --git a/fixtures/dom/src/components/FixtureSet.js b/fixtures/dom/src/components/FixtureSet.js index 9c6e8581eba4b..ff98b2884c1bb 100644 --- a/fixtures/dom/src/components/FixtureSet.js +++ b/fixtures/dom/src/components/FixtureSet.js @@ -1,8 +1,9 @@ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - title: React.PropTypes.node.isRequired, - description: React.PropTypes.node.isRequired, + title: PropTypes.node.isRequired, + description: PropTypes.node.isRequired, }; class FixtureSet extends React.Component { diff --git a/fixtures/dom/src/components/Header.js b/fixtures/dom/src/components/Header.js index d9732165c4248..6d1b32599fa8a 100644 --- a/fixtures/dom/src/components/Header.js +++ b/fixtures/dom/src/components/Header.js @@ -2,13 +2,14 @@ import { parse, stringify } from 'query-string'; import getVersionTags from '../tags'; const React = window.React; -const Header = React.createClass({ - getInitialState() { +class Header extends React.Component { + constructor(props, context) { + super(props, context); const query = parse(window.location.search); const version = query.version || 'local'; const versions = [version]; - return { version, versions }; - }, + this.state = { version, versions }; + } componentWillMount() { getVersionTags() .then(tags => { @@ -16,7 +17,7 @@ const Header = React.createClass({ versions = [`local`, ...versions]; this.setState({ versions }); }) - }, + } handleVersionChange(event) { const query = parse(window.location.search); query.version = event.target.value; @@ -24,10 +25,10 @@ const Header = React.createClass({ delete query.version; } window.location.search = stringify(query); - }, + } handleFixtureChange(event) { window.location.pathname = event.target.value; - }, + } render() { return (
@@ -66,7 +67,7 @@ const Header = React.createClass({
); - }, -}); + } +} export default Header; diff --git a/fixtures/dom/src/components/TestCase.js b/fixtures/dom/src/components/TestCase.js index 79c46a975afbc..053eac9467884 100644 --- a/fixtures/dom/src/components/TestCase.js +++ b/fixtures/dom/src/components/TestCase.js @@ -1,14 +1,15 @@ import cn from 'classnames'; import semver from 'semver'; import React from 'react'; +import PropTypes from 'prop-types'; import { parse } from 'query-string'; -import { semverString } from './propTypes' +import { semverString } from './propTypes'; const propTypes = { - children: React.PropTypes.node.isRequired, - title: React.PropTypes.node.isRequired, + children: PropTypes.node.isRequired, + title: PropTypes.node.isRequired, resolvedIn: semverString, - resolvedBy: React.PropTypes.string + resolvedBy: PropTypes.string }; class TestCase extends React.Component { diff --git a/fixtures/dom/src/components/fixtures/buttons/index.js b/fixtures/dom/src/components/fixtures/buttons/index.js index 4991f4e4d8c6b..e7182280d637b 100644 --- a/fixtures/dom/src/components/fixtures/buttons/index.js +++ b/fixtures/dom/src/components/fixtures/buttons/index.js @@ -10,7 +10,7 @@ function onButtonClick() { export default class ButtonTestCases extends React.Component { render() { return ( - + diff --git a/fixtures/dom/src/components/fixtures/index.js b/fixtures/dom/src/components/fixtures/index.js index adc5a3d16208e..27be0fe24f284 100644 --- a/fixtures/dom/src/components/fixtures/index.js +++ b/fixtures/dom/src/components/fixtures/index.js @@ -12,29 +12,27 @@ import ButtonFixtures from './buttons'; * A simple routing component that renders the appropriate * fixture based on the location pathname. */ -const FixturesPage = React.createClass({ - render() { - switch (window.location.pathname) { - case '/text-inputs': - return ; - case '/range-inputs': - return ; - case '/selects': - return ; - case '/textareas': - return ; - case '/input-change-events': - return ; - case '/number-inputs': - return ; - case '/password-inputs': - return ; - case '/buttons': - return - default: - return

Please select a test fixture.

; - } - }, -}); +function FixturesPage() { + switch (window.location.pathname) { + case '/text-inputs': + return ; + case '/range-inputs': + return ; + case '/selects': + return ; + case '/textareas': + return ; + case '/input-change-events': + return ; + case '/number-inputs': + return ; + case '/password-inputs': + return ; + case '/buttons': + return + default: + return

Please select a test fixture.

; + } +} module.exports = FixturesPage; diff --git a/fixtures/dom/src/components/fixtures/number-inputs/NumberTestCase.js b/fixtures/dom/src/components/fixtures/number-inputs/NumberTestCase.js index 2c072d478ebe4..1a3025c49323b 100644 --- a/fixtures/dom/src/components/fixtures/number-inputs/NumberTestCase.js +++ b/fixtures/dom/src/components/fixtures/number-inputs/NumberTestCase.js @@ -2,16 +2,14 @@ const React = window.React; import Fixture from '../../Fixture'; -const NumberTestCase = React.createClass({ - getInitialState() { - return { value: '' }; - }, - onChange(event) { +class NumberTestCase extends React.Component { + state = { value: '' }; + onChange = (event) => { const parsed = parseFloat(event.target.value, 10) const value = isNaN(parsed) ? '' : parsed this.setState({ value }) - }, + } render() { return ( @@ -31,7 +29,7 @@ const NumberTestCase = React.createClass({
); - }, -}); + } +} export default NumberTestCase; diff --git a/fixtures/dom/src/components/fixtures/number-inputs/index.js b/fixtures/dom/src/components/fixtures/number-inputs/index.js index 2c88c333edeb3..7900bd8594345 100644 --- a/fixtures/dom/src/components/fixtures/number-inputs/index.js +++ b/fixtures/dom/src/components/fixtures/number-inputs/index.js @@ -4,164 +4,162 @@ import FixtureSet from '../../FixtureSet'; import TestCase from '../../TestCase'; import NumberTestCase from './NumberTestCase'; -const NumberInputs = React.createClass({ - render() { - return ( - + - - -
  • Type "3.1"
  • -
  • Press backspace, eliminating the "1"
  • -
    - - - The field should read "3.", preserving the decimal place - - - - -

    - Notes: Chrome and Safari clear trailing - decimals on blur. React makes this concession so that the - value attribute remains in sync with the value property. -

    -
    - - - -
  • Type "0.01"
  • -
    - - - The field should read "0.01" - - - -
    - - - -
  • Type "2e"
  • -
  • Type 4, to read "2e4"
  • -
    - - - The field should read "2e4". The parsed value should read "20000" - - - -
    - - - -
  • Type "3.14"
  • -
  • Press "e", so that the input reads "3.14e"
  • -
    - - - The field should read "3.14e", the parsed value should be empty - - - -
    - - - -
  • Type "3.14"
  • -
  • Move the text cursor to after the decimal place
  • -
  • Press "e" twice, so that the value reads "3.ee14"
  • -
    - - - The field should read "3.ee14" - - - -
    - - - -
  • Type "3.0"
  • -
    - - - The field should read "3.0" - - - -
    - - - -
  • Type "300"
  • -
  • Move the cursor to after the "3"
  • -
  • Type "."
  • -
    - - - The field should read "3.00", not "3" - - -
    - - - -
  • Type "3"
  • -
  • Select the entire value"
  • -
  • Type '-' to replace '3' with '-'
  • -
    - - - The field should read "-", not be blank. - - -
    - - - -
  • Type "-"
  • -
  • Type '3'
  • -
    - - - The field should read "-3". - - -
    -
    - ); - }, -}); + +
  • Type "3.1"
  • +
  • Press backspace, eliminating the "1"
  • +
    + + + The field should read "3.", preserving the decimal place + + + + +

    + Notes: Chrome and Safari clear trailing + decimals on blur. React makes this concession so that the + value attribute remains in sync with the value property. +

    + + + + +
  • Type "0.01"
  • +
    + + + The field should read "0.01" + + + +
    + + + +
  • Type "2e"
  • +
  • Type 4, to read "2e4"
  • +
    + + + The field should read "2e4". The parsed value should read "20000" + + + +
    + + + +
  • Type "3.14"
  • +
  • Press "e", so that the input reads "3.14e"
  • +
    + + + The field should read "3.14e", the parsed value should be empty + + + +
    + + + +
  • Type "3.14"
  • +
  • Move the text cursor to after the decimal place
  • +
  • Press "e" twice, so that the value reads "3.ee14"
  • +
    + + + The field should read "3.ee14" + + + +
    + + + +
  • Type "3.0"
  • +
    + + + The field should read "3.0" + + + +
    + + + +
  • Type "300"
  • +
  • Move the cursor to after the "3"
  • +
  • Type "."
  • +
    + + + The field should read "3.00", not "3" + + +
    + + + +
  • Type "3"
  • +
  • Select the entire value"
  • +
  • Type '-' to replace '3' with '-'
  • +
    + + + The field should read "-", not be blank. + + +
    + + + +
  • Type "-"
  • +
  • Type '3'
  • +
    + + + The field should read "-3". + + +
    + + ); +} export default NumberInputs; diff --git a/fixtures/dom/src/components/fixtures/password-inputs/PasswordTestCase.js b/fixtures/dom/src/components/fixtures/password-inputs/PasswordTestCase.js index 76f511776369d..085ff760b646b 100644 --- a/fixtures/dom/src/components/fixtures/password-inputs/PasswordTestCase.js +++ b/fixtures/dom/src/components/fixtures/password-inputs/PasswordTestCase.js @@ -2,13 +2,11 @@ const React = window.React; import Fixture from '../../Fixture'; -const PasswordTestCase = React.createClass({ - getInitialState() { - return { value: '' }; - }, - onChange(event) { +class PasswordTestCase extends React.Component { + state = { value: '' }; + onChange = (event) => { this.setState({ value: event.target.value }) - }, + } render() { return ( @@ -28,7 +26,7 @@ const PasswordTestCase = React.createClass({
    ); - }, -}); + } +} export default PasswordTestCase; diff --git a/fixtures/dom/src/components/fixtures/password-inputs/index.js b/fixtures/dom/src/components/fixtures/password-inputs/index.js index 7c4094534bdad..bec39919781bf 100644 --- a/fixtures/dom/src/components/fixtures/password-inputs/index.js +++ b/fixtures/dom/src/components/fixtures/password-inputs/index.js @@ -4,30 +4,28 @@ import FixtureSet from '../../FixtureSet'; import TestCase from '../../TestCase'; import PasswordTestCase from './PasswordTestCase' -const NumberInputs = React.createClass({ - render() { - return ( - - - -
  • Type any string (not an actual password
  • -
    +function NumberInputs() { + return ( + + + +
  • Type any string (not an actual password
  • +
    - - The field should include the "unmasking password" icon. - + + The field should include the "unmasking password" icon. + - -
    -
    - ); - }, -}); + +
    +
    + ); +} export default NumberInputs; diff --git a/fixtures/dom/src/components/fixtures/range-inputs/index.js b/fixtures/dom/src/components/fixtures/range-inputs/index.js index e3be8ad2ce546..bea61f453e15b 100644 --- a/fixtures/dom/src/components/fixtures/range-inputs/index.js +++ b/fixtures/dom/src/components/fixtures/range-inputs/index.js @@ -1,12 +1,10 @@ const React = window.React; -const RangeInputs = React.createClass({ - getInitialState() { - return { value: 0.5 }; - }, - onChange(event) { +class RangeInputs extends React.Component { + state = { value: 0.5 }; + onChange = (event) => { this.setState({ value: event.target.value }); - }, + } render() { return (
    @@ -22,7 +20,7 @@ const RangeInputs = React.createClass({
    ); - }, -}); + } +} export default RangeInputs; diff --git a/fixtures/dom/src/components/fixtures/selects/index.js b/fixtures/dom/src/components/fixtures/selects/index.js index c991da7ce381f..a520e40c3b92f 100644 --- a/fixtures/dom/src/components/fixtures/selects/index.js +++ b/fixtures/dom/src/components/fixtures/selects/index.js @@ -1,12 +1,10 @@ const React = window.React; -const SelectFixture = React.createClass({ - getInitialState() { - return { value: '' }; - }, - onChange(event) { +class SelectFixture extends React.Component { + state = { value: '' }; + onChange = (event) => { this.setState({ value: event.target.value }); - }, + } render() { return (
    @@ -31,7 +29,7 @@ const SelectFixture = React.createClass({
    ); - }, -}); + } +} export default SelectFixture; diff --git a/fixtures/dom/src/components/fixtures/text-inputs/index.js b/fixtures/dom/src/components/fixtures/text-inputs/index.js index 2db132bcb1032..a1683672ce66b 100644 --- a/fixtures/dom/src/components/fixtures/text-inputs/index.js +++ b/fixtures/dom/src/components/fixtures/text-inputs/index.js @@ -1,13 +1,11 @@ const React = window.React; -const TextInputFixtures = React.createClass({ - getInitialState() { - return { - color: '#ffaaee', - }; - }, +class TextInputFixtures extends React.Component { + state = { + color: '#ffaaee', + }; - renderControlled(type) { + renderControlled = (type) => { let id = `controlled_${type}`; let onChange = e => { @@ -29,9 +27,9 @@ const TextInputFixtures = React.createClass({   → {JSON.stringify(state)}
    ); - }, + } - renderUncontrolled(type) { + renderUncontrolled = (type) => { let id = `uncontrolled_${type}`; return (
    @@ -39,7 +37,7 @@ const TextInputFixtures = React.createClass({
    ); - }, + } render() { // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input @@ -60,7 +58,7 @@ const TextInputFixtures = React.createClass({ ); - }, -}); + } +} module.exports = TextInputFixtures; diff --git a/fixtures/dom/src/components/fixtures/textareas/index.js b/fixtures/dom/src/components/fixtures/textareas/index.js index e39b2e2abf7f7..e2508f32b52c5 100644 --- a/fixtures/dom/src/components/fixtures/textareas/index.js +++ b/fixtures/dom/src/components/fixtures/textareas/index.js @@ -1,12 +1,10 @@ const React = window.React; -const TextAreaFixtures = React.createClass({ - getInitialState() { - return { value: '' }; - }, - onChange(event) { +class TextAreaFixtures extends React.Component { + state = { value: '' }; + onChange = (event) => { this.setState({ value: event.target.value }); - }, + } render() { return (
    @@ -30,7 +28,7 @@ const TextAreaFixtures = React.createClass({
    ); - }, -}); + } +} module.exports = TextAreaFixtures; diff --git a/fixtures/dom/src/components/propTypes.js b/fixtures/dom/src/components/propTypes.js index 42f4f4cf3ae27..dfb80d0a99b81 100644 --- a/fixtures/dom/src/components/propTypes.js +++ b/fixtures/dom/src/components/propTypes.js @@ -1,11 +1,10 @@ +import PropTypes from 'prop-types'; import semver from 'semver'; -const React = window.React; - export function semverString (props, propName, componentName) { let version = props[propName]; - let error = React.PropTypes.string(...arguments); + let error = PropTypes.string(...arguments); if (!error && version != null && !semver.valid(version)) error = new Error( `\`${propName}\` should be a valid "semantic version" matching ` + diff --git a/fixtures/dom/yarn.lock b/fixtures/dom/yarn.lock index e45c4a70540d7..762b52cfc093b 100644 --- a/fixtures/dom/yarn.lock +++ b/fixtures/dom/yarn.lock @@ -4239,6 +4239,12 @@ promise@7.1.1, promise@^7.1.1: dependencies: asap "~2.0.3" +prop-types@^15.5.6: + version "15.5.6" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.6.tgz#797a915b1714b645ebb7c5d6cc690346205bd2aa" + dependencies: + fbjs "^0.8.9" + proxy-addr@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" diff --git a/package.json b/package.json index c8cf86911ae0a..c8c55229203dc 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "coffee-script": "^1.8.0", "core-js": "^2.2.1", "coveralls": "^2.11.6", - "create-react-class": "^15.5.0", + "create-react-class": "^15.5.2", "del": "^2.0.2", "derequire": "^2.0.3", "escape-string-regexp": "^1.0.5", @@ -73,6 +73,7 @@ "object-assign": "^4.1.1", "platform": "^1.1.0", "prettier": "^0.22.0", + "prop-types": "^15.5.6", "rimraf": "^2.6.1", "rollup": "^0.41.6", "rollup-plugin-alias": "^1.2.1", diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json index a4a7f48e9a93e..0dae9585dfe72 100644 --- a/packages/react-dom/package.json +++ b/packages/react-dom/package.json @@ -15,7 +15,8 @@ "dependencies": { "fbjs": "^0.8.9", "loose-envify": "^1.1.0", - "object-assign": "^4.1.0" + "object-assign": "^4.1.0", + "prop-types": "^15.5.6" }, "peerDependencies": { "react": "^16.0.0-alpha.8" diff --git a/packages/react/package.json b/packages/react/package.json index 1fc717340ef0f..134466884dc89 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -22,9 +22,11 @@ "node": ">=0.10.0" }, "dependencies": { + "create-react-class": "^15.5.2", "fbjs": "^0.8.9", "loose-envify": "^1.1.0", - "object-assign": "^4.1.0" + "object-assign": "^4.1.0", + "prop-types": "^15.5.6" }, "browserify": { "transform": [ diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 89dc4c89febb1..485f3921f4f45 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -45,6 +45,8 @@ scripts/shared/__tests__/evalToString-test.js src/isomorphic/__tests__/React-test.js * should log a deprecation warning once when using React.createMixin * should warn once when attempting to access React.createClass +* should warn once when attempting to access React.PropTypes +* should warn once when attempting to access React.checkPropTypes src/isomorphic/children/__tests__/ReactChildren-test.js * should support identity for simple @@ -278,19 +280,6 @@ src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js * should have received the validator's return value * should not warn if the validator returned null -src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should be a no-op -* should not have been called - src/isomorphic/modern/class/__tests__/ReactClassEquivalence-test.js * tests the same thing for es6 classes and CoffeeScript * tests the same thing for es6 classes and TypeScript diff --git a/scripts/jest/ts-preprocessor.js b/scripts/jest/ts-preprocessor.js index b4fe74552c40f..29ad307a9a392 100644 --- a/scripts/jest/ts-preprocessor.js +++ b/scripts/jest/ts-preprocessor.js @@ -23,7 +23,7 @@ function compile(content, contentFilename) { getSourceFile(filename, languageVersion) { var source; var jestRegex = /jest\.d\.ts/; - var reactRegex = /(?:React|ReactDOM)(?:\.d)?\.ts$/; + var reactRegex = /(?:React|ReactDOM|PropTypes)(?:\.d)?\.ts$/; // `path.normalize` is used to turn forward slashes in // the file path into backslashes on Windows. diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 69b04f0b73d0f..cc33df8d123e8 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -45,7 +45,12 @@ const bundles = [ sourceMap: false, }, entry: 'src/isomorphic/React.js', - externals: [], + externals: [ + 'create-react-class/factory', + 'prop-types', + 'prop-types/checkPropTypes', + 'prop-types/factory', + ], fbEntry: 'src/fb/ReactFBEntry.js', hasteName: 'React', isRenderer: false, @@ -74,7 +79,7 @@ const bundles = [ sourceMap: false, }, entry: 'src/renderers/dom/ReactDOM.js', - externals: [], + externals: ['prop-types', 'prop-types/checkPropTypes'], fbEntry: 'src/fb/ReactDOMFBEntry.js', hasteName: 'ReactDOMStack', isRenderer: true, @@ -86,6 +91,7 @@ const bundles = [ 'src/renderers/shared/**/*.js', 'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM. + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -102,7 +108,7 @@ const bundles = [ sourceMap: false, }, entry: 'src/renderers/dom/fiber/ReactDOMFiber.js', - externals: [], + externals: ['prop-types', 'prop-types/checkPropTypes'], fbEntry: 'src/fb/ReactDOMFiberFBEntry.js', hasteName: 'ReactDOMFiber', isRenderer: true, @@ -114,6 +120,7 @@ const bundles = [ 'src/renderers/shared/**/*.js', 'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM. + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -133,7 +140,7 @@ const bundles = [ sourceMap: false, }, entry: 'src/renderers/dom/ReactDOMServer.js', - externals: [], + externals: ['prop-types', 'prop-types/checkPropTypes'], fbEntry: 'src/renderers/dom/ReactDOMServer.js', hasteName: 'ReactDOMServerStack', isRenderer: true, @@ -144,6 +151,7 @@ const bundles = [ 'src/renderers/dom/**/*.js', 'src/renderers/shared/**/*.js', + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -169,6 +177,7 @@ const bundles = [ 'art/modes/current', 'art/modes/fast-noSideEffects', 'art/core/transform', + 'prop-types/checkPropTypes', 'react-dom', ], fbEntry: 'src/renderers/art/ReactARTStack.js', @@ -181,6 +190,7 @@ const bundles = [ 'src/renderers/art/**/*.js', 'src/renderers/shared/**/*.js', + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -203,6 +213,7 @@ const bundles = [ 'art/modes/current', 'art/modes/fast-noSideEffects', 'art/core/transform', + 'prop-types/checkPropTypes', 'react-dom', ], fbEntry: 'src/renderers/art/ReactARTFiber.js', @@ -215,6 +226,7 @@ const bundles = [ 'src/renderers/art/**/*.js', 'src/renderers/shared/**/*.js', + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -304,7 +316,7 @@ const bundles = [ sourceMap: false, }, entry: 'src/renderers/testing/ReactTestRendererFiber', - externals: [], + externals: ['prop-types/checkPropTypes'], fbEntry: 'src/renderers/testing/ReactTestRendererFiber', hasteName: 'ReactTestRendererFiber', isRenderer: true, @@ -316,6 +328,7 @@ const bundles = [ 'src/renderers/shared/**/*.js', 'src/renderers/testing/**/*.js', + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -330,7 +343,7 @@ const bundles = [ sourceMap: false, }, entry: 'src/renderers/testing/stack/ReactTestRendererStack', - externals: [], + externals: ['prop-types/checkPropTypes'], fbEntry: 'src/renderers/testing/stack/ReactTestRendererStack', hasteName: 'ReactTestRendererStack', isRenderer: true, @@ -342,6 +355,7 @@ const bundles = [ 'src/renderers/shared/**/*.js', 'src/renderers/testing/**/*.js', + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], @@ -360,7 +374,7 @@ const bundles = [ sourceMap: false, }, entry: 'src/renderers/noop/ReactNoop.js', - externals: [], + externals: ['prop-types/checkPropTypes'], isRenderer: true, label: 'noop-fiber', manglePropertiesOnProd: false, @@ -369,6 +383,7 @@ const bundles = [ 'src/renderers/noop/**/*.js', 'src/renderers/shared/**/*.js', + 'src/isomorphic/classic/types/checkPropTypes.js', 'src/ReactVersion.js', 'src/shared/**/*.js', ], diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index 801b94e3c4f43..985fe8869087a 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -52,6 +52,14 @@ const devOnlyFilesToStubOut = [ "'ReactTestUtils'", ]; +const legacyModules = [ + 'create-react-class', + 'create-react-class/factory', + 'prop-types', + 'prop-types/checkPropTypes', + 'prop-types/factory', +]; + // this function builds up a very niave Haste-like moduleMap // that works to create up an alias map for modules to link // up to their actual disk location so Rollup can properly @@ -230,6 +238,29 @@ function replaceDevOnlyStubbedModules(bundleType) { } } +function replaceLegacyModuleAliases(bundleType) { + switch (bundleType) { + case UMD_DEV: + case UMD_PROD: + const modulesAlias = {}; + legacyModules.forEach(legacyModule => { + const modulePath = legacyModule.includes('/') + ? legacyModule + : `${legacyModule}/index`; + const resolvedPath = resolve(`./node_modules/${modulePath}`); + modulesAlias[`'${legacyModule}'`] = `'${resolvedPath}'`; + }); + return modulesAlias; + case NODE_DEV: + case NODE_PROD: + case FB_DEV: + case FB_PROD: + case RN_DEV: + case RN_PROD: + return {}; + } +} + function getAliases(paths, bundleType, isRenderer, extractErrors) { return Object.assign( createModuleMap( @@ -247,7 +278,8 @@ function getDefaultReplaceModules(bundleType) { return Object.assign( {}, replaceFbjsModuleAliases(bundleType), - replaceDevOnlyStubbedModules(bundleType) + replaceDevOnlyStubbedModules(bundleType), + replaceLegacyModuleAliases(bundleType) ); } diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index 88406fe9dfaaf..d676282dc3bff 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,117 +1,117 @@ { - "branch": "bundle-fixes", + "branch": "prop-types", "bundleSizes": { "react.development.js (UMD_DEV)": { - "size": 116098, - "gzip": 29520 + "size": 121474, + "gzip": 30524 }, "react.production.min.js (UMD_PROD)": { - "size": 13707, - "gzip": 5073 + "size": 15685, + "gzip": 5765 }, "react-dom.development.js (UMD_DEV)": { - "size": 563844, - "gzip": 130190 + "size": 583352, + "gzip": 134572 }, "react-dom.production.min.js (UMD_PROD)": { - "size": 120191, - "gzip": 37860 + "size": 120740, + "gzip": 38092 }, "react-dom-server.development.js (UMD_DEV)": { - "size": 476049, - "gzip": 115267 + "size": 495558, + "gzip": 119685 }, "react-dom-server.production.min.js (UMD_PROD)": { - "size": 106489, - "gzip": 33035 + "size": 107033, + "gzip": 33273 }, "react-art.development.js (UMD_DEV)": { - "size": 339929, - "gzip": 76018 + "size": 342770, + "gzip": 76828 }, "react-art.production.min.js (UMD_PROD)": { "size": 95013, - "gzip": 28991 + "gzip": 28990 }, "react.development.js (NODE_DEV)": { - "size": 109110, - "gzip": 27479 + "size": 70286, + "gzip": 17600 }, "react.production.min.js (NODE_PROD)": { - "size": 12598, - "gzip": 4649 + "size": 9226, + "gzip": 3626 }, "React-dev.js (FB_DEV)": { - "size": 110875, - "gzip": 28140 + "size": 72143, + "gzip": 18236 }, "React-prod.js (FB_PROD)": { - "size": 56406, - "gzip": 14416 + "size": 36643, + "gzip": 9256 }, "ReactDOMStack-dev.js (FB_DEV)": { - "size": 522626, - "gzip": 124708 + "size": 522763, + "gzip": 124727 }, "ReactDOMStack-prod.js (FB_PROD)": { - "size": 352708, - "gzip": 84660 + "size": 352776, + "gzip": 84675 }, "react-dom.development.js (NODE_DEV)": { - "size": 542218, - "gzip": 125162 + "size": 542350, + "gzip": 125199 }, "react-dom.production.min.js (NODE_PROD)": { - "size": 116858, - "gzip": 36717 + "size": 116925, + "gzip": 36732 }, "ReactDOMFiber-dev.js (FB_DEV)": { - "size": 797268, - "gzip": 184134 + "size": 797397, + "gzip": 184161 }, "ReactDOMFiber-prod.js (FB_PROD)": { - "size": 407540, - "gzip": 93567 + "size": 407613, + "gzip": 93586 }, "react-dom-server.development.js (NODE_DEV)": { - "size": 445452, - "gzip": 107574 + "size": 445589, + "gzip": 107597 }, "react-dom-server.production.min.js (NODE_PROD)": { - "size": 101344, - "gzip": 31273 + "size": 101411, + "gzip": 31292 }, "ReactDOMServerStack-dev.js (FB_DEV)": { - "size": 444144, - "gzip": 107423 + "size": 444281, + "gzip": 107443 }, "ReactDOMServerStack-prod.js (FB_PROD)": { - "size": 333744, - "gzip": 80424 + "size": 334166, + "gzip": 80444 }, "ReactARTStack-dev.js (FB_DEV)": { - "size": 141589, - "gzip": 32280 + "size": 142986, + "gzip": 32714 }, "ReactARTStack-prod.js (FB_PROD)": { - "size": 99762, - "gzip": 22576 + "size": 101143, + "gzip": 22993 }, "react-art.development.js (NODE_DEV)": { - "size": 265123, - "gzip": 56951 + "size": 265214, + "gzip": 56974 }, "react-art.production.min.js (NODE_PROD)": { - "size": 56591, - "gzip": 17132 + "size": 56628, + "gzip": 17152 }, "ReactARTFiber-dev.js (FB_DEV)": { - "size": 264301, - "gzip": 56758 + "size": 264392, + "gzip": 56780 }, "ReactARTFiber-prod.js (FB_PROD)": { - "size": 205292, - "gzip": 43132 + "size": 205336, + "gzip": 43154 }, "ReactNativeStack.js (RN)": { "size": 233993, @@ -122,20 +122,20 @@ "gzip": 84001 }, "ReactTestRendererFiber-dev.js (FB_DEV)": { - "size": 262210, - "gzip": 55722 + "size": 262301, + "gzip": 55747 }, "ReactTestRendererStack-dev.js (FB_DEV)": { - "size": 151425, - "gzip": 34728 + "size": 151521, + "gzip": 34765 }, "react-noop-renderer.development.js (NODE_DEV)": { - "size": 254207, - "gzip": 53701 + "size": 254298, + "gzip": 53728 }, "react-test-renderer.development.js (NODE_DEV)": { - "size": 263041, - "gzip": 55919 + "size": 263132, + "gzip": 55938 } } } \ No newline at end of file diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index ccc351225edb8..807a1c369f4f5 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -20,6 +20,7 @@ var ReactVersion = require('ReactVersion'); var onlyChild = require('onlyChild'); var checkPropTypes = require('checkPropTypes'); +var createReactClass = require('createClass'); var createElement = ReactElement.createElement; var createFactory = ReactElement.createFactory; @@ -56,11 +57,13 @@ var React = { cloneElement: cloneElement, isValidElement: ReactElement.isValidElement, + // TODO (bvaughn) Remove these getters in 16.0.0-alpha.10 + PropTypes: ReactPropTypes, checkPropTypes: checkPropTypes, + createClass: createReactClass, // Classic - PropTypes: ReactPropTypes, createFactory: createFactory, createMixin: createMixin, @@ -82,8 +85,10 @@ if (__DEV__) { ReactDebugCurrentFrame: require('ReactDebugCurrentFrame'), }); + let warnedForCheckPropTypes = false; let warnedForCreateMixin = false; let warnedForCreateClass = false; + let warnedForPropTypes = false; React.createMixin = function(mixin) { warning( @@ -95,18 +100,49 @@ if (__DEV__) { return mixin; }; + // TODO (bvaughn) Remove both of these deprecation warnings in 16.0.0-alpha.10 if (canDefineProperty) { + Object.defineProperty(React, 'checkPropTypes', { + get() { + warning( + warnedForCheckPropTypes, + 'checkPropTypes has been moved to a separate package. ' + + 'Accessing React.checkPropTypes is no longer supported ' + + 'and will be removed completely in React 16. ' + + 'Use the prop-types package on npm instead. ' + + '(https://fb.me/migrating-from-react-proptypes)', + ); + warnedForCheckPropTypes = true; + return ReactPropTypes; + }, + }); + Object.defineProperty(React, 'createClass', { get: function() { warning( warnedForCreateClass, 'React.createClass is no longer supported. Use a plain JavaScript ' + "class instead. If you're not yet ready to migrate, " + - 'create-react-class is available on npm as a temporary, ' + - 'drop-in replacement.', + 'create-react-class is available on npm as a drop-in replacement. ' + + '(https://fb.me/migrating-from-react-create-class)', ); warnedForCreateClass = true; - return undefined; + return createReactClass; + }, + }); + + Object.defineProperty(React, 'PropTypes', { + get() { + warning( + warnedForPropTypes, + 'PropTypes has been moved to a separate package. ' + + 'Accessing React.PropTypes is no longer supported ' + + 'and will be removed completely in React 16. ' + + 'Use the prop-types package on npm instead. ' + + '(https://fb.me/migrating-from-react-proptypes)', + ); + warnedForPropTypes = true; + return ReactPropTypes; }, }); } diff --git a/src/isomorphic/__tests__/React-test.js b/src/isomorphic/__tests__/React-test.js index f2ea926dd9a08..bd5d5bc1aaa4b 100644 --- a/src/isomorphic/__tests__/React-test.js +++ b/src/isomorphic/__tests__/React-test.js @@ -32,13 +32,43 @@ describe('React', () => { spyOn(console, 'error'); let createClass = React.createClass; createClass = React.createClass; - expect(createClass).toBe(undefined); + expect(createClass).not.toBe(undefined); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'React.createClass is no longer supported. Use a plain ' + - "JavaScript class instead. If you're not yet ready to migrate, " + - 'create-react-class is available on npm as a temporary, ' + - 'drop-in replacement.', + 'React.createClass is no longer supported. Use a plain JavaScript ' + + "class instead. If you're not yet ready to migrate, " + + 'create-react-class is available on npm as a drop-in replacement. ' + + '(https://fb.me/migrating-from-react-create-class)', + ); + }); + + it('should warn once when attempting to access React.PropTypes', () => { + spyOn(console, 'error'); + let PropTypes = React.PropTypes; + PropTypes = React.PropTypes; + expect(PropTypes).not.toBe(undefined); + expectDev(console.error.calls.count()).toBe(1); + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'PropTypes has been moved to a separate package. ' + + 'Accessing React.PropTypes is no longer supported ' + + 'and will be removed completely in React 16. ' + + 'Use the prop-types package on npm instead. ' + + '(https://fb.me/migrating-from-react-proptypes)', + ); + }); + + it('should warn once when attempting to access React.checkPropTypes', () => { + spyOn(console, 'error'); + let checkPropTypes = React.checkPropTypes; + checkPropTypes = React.checkPropTypes; + expect(checkPropTypes).not.toBe(undefined); + expectDev(console.error.calls.count()).toBe(1); + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'checkPropTypes has been moved to a separate package. ' + + 'Accessing React.checkPropTypes is no longer supported ' + + 'and will be removed completely in React 16. ' + + 'Use the prop-types package on npm instead. ' + + '(https://fb.me/migrating-from-react-proptypes)', ); }); }); diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js index 84a220877f8cb..0630f588cc7a2 100644 --- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js +++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js @@ -17,6 +17,7 @@ 'use strict'; +var PropTypes; var React; var ReactDOM; var ReactTestUtils; @@ -29,6 +30,7 @@ describe('ReactContextValidator', () => { beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); @@ -44,7 +46,7 @@ describe('ReactContextValidator', () => { } } Component.contextTypes = { - foo: React.PropTypes.string, + foo: PropTypes.string, }; class ComponentInFooBarContext extends React.Component { @@ -60,8 +62,8 @@ describe('ReactContextValidator', () => { } } ComponentInFooBarContext.childContextTypes = { - foo: React.PropTypes.string, - bar: React.PropTypes.number, + foo: PropTypes.string, + bar: PropTypes.number, }; var instance = ReactTestUtils.renderIntoDocument( @@ -88,8 +90,8 @@ describe('ReactContextValidator', () => { } } Parent.childContextTypes = { - foo: React.PropTypes.string.isRequired, - bar: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, + bar: PropTypes.string.isRequired, }; class Component extends React.Component { @@ -112,7 +114,7 @@ describe('ReactContextValidator', () => { } } Component.contextTypes = { - foo: React.PropTypes.string, + foo: PropTypes.string, }; var container = document.createElement('div'); @@ -139,8 +141,8 @@ describe('ReactContextValidator', () => { } } Parent.childContextTypes = { - foo: React.PropTypes.string.isRequired, - bar: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, + bar: PropTypes.string.isRequired, }; class Component extends React.Component { @@ -153,7 +155,7 @@ describe('ReactContextValidator', () => { } } Component.contextTypes = { - foo: React.PropTypes.string, + foo: PropTypes.string, }; var container = document.createElement('div'); @@ -171,7 +173,7 @@ describe('ReactContextValidator', () => { } } Component.contextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; ReactTestUtils.renderIntoDocument(); @@ -196,7 +198,7 @@ describe('ReactContextValidator', () => { } } ComponentInFooStringContext.childContextTypes = { - foo: React.PropTypes.string, + foo: PropTypes.string, }; ReactTestUtils.renderIntoDocument( @@ -218,7 +220,7 @@ describe('ReactContextValidator', () => { } } ComponentInFooNumberContext.childContextTypes = { - foo: React.PropTypes.number, + foo: PropTypes.number, }; ReactTestUtils.renderIntoDocument( @@ -248,8 +250,8 @@ describe('ReactContextValidator', () => { } } Component.childContextTypes = { - foo: React.PropTypes.string.isRequired, - bar: React.PropTypes.number, + foo: PropTypes.string.isRequired, + bar: PropTypes.number, }; ReactTestUtils.renderIntoDocument(); @@ -288,7 +290,7 @@ describe('ReactContextValidator', () => { class ComponentA extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; render() { return
    ; @@ -296,7 +298,7 @@ describe('ReactContextValidator', () => { } class ComponentB extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; render() { return
    ; @@ -330,7 +332,7 @@ describe('ReactContextValidator', () => { class ParentContextProvider extends React.Component { static childContextTypes = { - foo: React.PropTypes.number, + foo: PropTypes.number, }; getChildContext() { return { @@ -344,7 +346,7 @@ describe('ReactContextValidator', () => { class MiddleMissingContext extends React.Component { static childContextTypes = { - bar: React.PropTypes.string.isRequired, + bar: PropTypes.string.isRequired, }; render() { return ; @@ -359,8 +361,8 @@ describe('ReactContextValidator', () => { } } ChildContextConsumer.contextTypes = { - bar: React.PropTypes.string.isRequired, - foo: React.PropTypes.string.isRequired, + bar: PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; ReactTestUtils.renderIntoDocument(); diff --git a/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js index 3eddc9730524c..55fb8c1ed8a49 100644 --- a/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js +++ b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactDOM; var ReactTestUtils; @@ -18,8 +19,9 @@ var createReactClass; describe('create-react-class-integration', () => { beforeEach(() => { - React = require('React'); - ReactDOM = require('ReactDOM'); + PropTypes = require('prop-types'); + React = require('react'); + ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); var createReactClassFactory = require('create-react-class/factory'); createReactClass = createReactClassFactory( @@ -188,13 +190,13 @@ describe('create-react-class-integration', () => { createReactClass({ mixins: [{}], propTypes: { - foo: React.PropTypes.string, + foo: PropTypes.string, }, contextTypes: { - foo: React.PropTypes.string, + foo: PropTypes.string, }, childContextTypes: { - foo: React.PropTypes.string, + foo: PropTypes.string, }, render: function() { return
    ; @@ -268,7 +270,7 @@ describe('create-react-class-integration', () => { it('renders based on context getInitialState', () => { var Foo = createReactClass({ contextTypes: { - className: React.PropTypes.string, + className: PropTypes.string, }, getInitialState() { return {className: this.context.className}; @@ -280,7 +282,7 @@ describe('create-react-class-integration', () => { var Outer = createReactClass({ childContextTypes: { - className: React.PropTypes.string, + className: PropTypes.string, }, getChildContext() { return {className: 'foo'}; 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/isomorphic/classic/element/__tests__/ReactElementClone-test.js b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js index 827509b196ea4..365b187d24391 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactDOM; var ReactTestUtils; @@ -19,6 +20,7 @@ describe('ReactElementClone', () => { var ComponentClass; beforeEach(() => { + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); @@ -288,13 +290,13 @@ describe('ReactElementClone', () => { it('should check declared prop types after clone', () => { spyOn(console, 'error'); class Component extends React.Component { + static propTypes = { + color: PropTypes.string.isRequired, + }; render() { return React.createElement('div', null, 'My color is ' + this.color); } } - Component.propTypes = { - color: React.PropTypes.string.isRequired, - }; class Parent extends React.Component { render() { return React.cloneElement(this.props.child, {color: 123}); diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js index ada2bb20fa7ec..69bb8fd512b8d 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js @@ -14,6 +14,7 @@ // NOTE: We're explicitly not using JSX in this file. This is intended to test // classic JS without JSX. +var PropTypes; var React; var ReactDOM; var ReactTestUtils; @@ -28,6 +29,7 @@ describe('ReactElementValidator', () => { beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); @@ -247,7 +249,7 @@ describe('ReactElementValidator', () => { return React.createElement('div', null, 'My color is ' + props.color); } MyComp.propTypes = { - color: React.PropTypes.string, + color: PropTypes.string, }; function ParentComp() { return React.createElement(MyComp, {color: 123}); @@ -332,12 +334,12 @@ describe('ReactElementValidator', () => { spyOn(console, 'error'); class Component extends React.Component { + static propTypes = {prop: PropTypes.string.isRequired}; + static defaultProps = {prop: null}; 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)); @@ -353,12 +355,12 @@ describe('ReactElementValidator', () => { spyOn(console, 'error'); class Component extends React.Component { + static propTypes = {prop: PropTypes.string.isRequired}; + static defaultProps = {prop: 'text'}; 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}), @@ -376,13 +378,13 @@ describe('ReactElementValidator', () => { spyOn(console, 'error'); class Component extends React.Component { + static propTypes = { + prop: PropTypes.string.isRequired, + }; render() { return React.createElement('span', null, this.props.prop); } } - Component.propTypes = { - prop: React.PropTypes.string.isRequired, - }; ReactTestUtils.renderIntoDocument(React.createElement(Component)); ReactTestUtils.renderIntoDocument( @@ -416,13 +418,13 @@ describe('ReactElementValidator', () => { spyOn(console, 'error'); class Component extends React.Component { + static propTypes = { + myProp: PropTypes.shape, + }; render() { return React.createElement('span', null, this.props.myProp.value); } } - Component.propTypes = { - myProp: React.PropTypes.shape, - }; ReactTestUtils.renderIntoDocument( React.createElement(Component, {myProp: {value: 'hi'}}), diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index 01710a0086694..5c0ca77351039 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -11,548 +11,7 @@ 'use strict'; -var ReactElement = require('ReactElement'); -var ReactPropTypesSecret = require('ReactPropTypesSecret'); +var {isValidElement} = require('ReactElement'); +var factory = require('prop-types/factory'); -var emptyFunction = require('fbjs/lib/emptyFunction'); -var getIteratorFn = require('getIteratorFn'); -var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); - -/** - * Collection of methods that allow declaration and validation of props that are - * supplied to React components. Example usage: - * - * var Props = require('ReactPropTypes'); - * var MyArticle = React.createClass({ - * propTypes: { - * // An optional string prop named "description". - * description: Props.string, - * - * // A required enum prop named "category". - * category: Props.oneOf(['News','Photos']).isRequired, - * - * // A prop named "dialog" that requires an instance of Dialog. - * dialog: Props.instanceOf(Dialog).isRequired - * }, - * render: function() { ... } - * }); - * - * A more formal specification of how these methods are used: - * - * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) - * decl := ReactPropTypes.{type}(.isRequired)? - * - * Each and every declaration produces a function with the same signature. This - * allows the creation of custom validation functions. For example: - * - * var MyLink = React.createClass({ - * propTypes: { - * // An optional string or URI prop named "href". - * href: function(props, propName, componentName) { - * var propValue = props[propName]; - * if (propValue != null && typeof propValue !== 'string' && - * !(propValue instanceof URI)) { - * return new Error( - * 'Expected a string or an URI for ' + propName + ' in ' + - * componentName - * ); - * } - * } - * }, - * render: function() {...} - * }); - * - * @internal - */ - -var ANONYMOUS = '<>'; - -var ReactPropTypes; - -if (__DEV__) { - // Keep in sync with production version below - ReactPropTypes = { - array: createPrimitiveTypeChecker('array'), - bool: createPrimitiveTypeChecker('boolean'), - func: createPrimitiveTypeChecker('function'), - number: createPrimitiveTypeChecker('number'), - object: createPrimitiveTypeChecker('object'), - string: createPrimitiveTypeChecker('string'), - symbol: createPrimitiveTypeChecker('symbol'), - - any: createAnyTypeChecker(), - arrayOf: createArrayOfTypeChecker, - element: createElementTypeChecker(), - instanceOf: createInstanceTypeChecker, - node: createNodeChecker(), - objectOf: createObjectOfTypeChecker, - oneOf: createEnumTypeChecker, - oneOfType: createUnionTypeChecker, - shape: createShapeTypeChecker, - }; -} else { - var productionTypeChecker = function() { - invariant( - false, - 'React.PropTypes type checking code is stripped in production.', - ); - }; - productionTypeChecker.isRequired = productionTypeChecker; - var getProductionTypeChecker = () => productionTypeChecker; - // Keep in sync with development version above - ReactPropTypes = { - array: productionTypeChecker, - bool: productionTypeChecker, - func: productionTypeChecker, - number: productionTypeChecker, - object: productionTypeChecker, - string: productionTypeChecker, - symbol: productionTypeChecker, - - any: productionTypeChecker, - arrayOf: getProductionTypeChecker, - element: productionTypeChecker, - instanceOf: getProductionTypeChecker, - node: productionTypeChecker, - objectOf: getProductionTypeChecker, - oneOf: getProductionTypeChecker, - oneOfType: getProductionTypeChecker, - shape: getProductionTypeChecker, - }; -} - -/** - * inlined Object.is polyfill to avoid requiring consumers ship their own - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - */ -/*eslint-disable no-self-compare*/ -function is(x, y) { - // SameValue algorithm - if (x === y) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - return x !== 0 || 1 / x === 1 / y; - } else { - // Step 6.a: NaN == NaN - return x !== x && y !== y; - } -} -/*eslint-enable no-self-compare*/ - -/** - * We use an Error-like object for backward compatibility as people may call - * PropTypes directly and inspect their output. However, we don't use real - * Errors anymore. We don't inspect their stack anyway, and creating them - * is prohibitively expensive if they are created too often, such as what - * happens in oneOfType() for any type before the one that matched. - */ -function PropTypeError(message) { - this.message = message; - this.stack = ''; -} -// Make `instanceof Error` still work for returned errors. -PropTypeError.prototype = Error.prototype; - -function createChainableTypeChecker(validate) { - if (__DEV__) { - var manualPropTypeCallCache = {}; - } - function checkType( - isRequired, - props, - propName, - componentName, - location, - propFullName, - secret, - ) { - componentName = componentName || ANONYMOUS; - propFullName = propFullName || propName; - if (__DEV__) { - if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') { - var cacheKey = `${componentName}:${propName}`; - if (!manualPropTypeCallCache[cacheKey]) { - warning( - false, - 'You are manually calling a React.PropTypes validation ' + - 'function for the `%s` prop on `%s`. This is deprecated ' + - 'and will not work in production with the next major version. ' + - 'You may be seeing this warning due to a third-party PropTypes ' + - 'library. See https://fb.me/react-warning-dont-call-proptypes ' + - 'for details.', - propFullName, - componentName, - ); - manualPropTypeCallCache[cacheKey] = true; - } - } - } - if (props[propName] == null) { - if (isRequired) { - if (props[propName] === null) { - return new PropTypeError( - `The ${location} \`${propFullName}\` is marked as required ` + - `in \`${componentName}\`, but its value is \`null\`.`, - ); - } - return new PropTypeError( - `The ${location} \`${propFullName}\` is marked as required in ` + - `\`${componentName}\`, but its value is \`undefined\`.`, - ); - } - return null; - } else { - return validate(props, propName, componentName, location, propFullName); - } - } - - var chainedCheckType = checkType.bind(null, false); - chainedCheckType.isRequired = checkType.bind(null, true); - - return chainedCheckType; -} - -function createPrimitiveTypeChecker(expectedType) { - function validate( - props, - propName, - componentName, - location, - propFullName, - secret, - ) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== expectedType) { - // `propValue` being instance of, say, date/regexp, pass the 'object' - // check, but we can offer a more precise error message here rather than - // 'of type `object`'. - var preciseType = getPreciseType(propValue); - - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of type ` + - `\`${preciseType}\` supplied to \`${componentName}\`, expected ` + - `\`${expectedType}\`.`, - ); - } - return null; - } - return createChainableTypeChecker(validate); -} - -function createAnyTypeChecker() { - return createChainableTypeChecker(emptyFunction.thatReturnsNull); -} - -function createArrayOfTypeChecker(typeChecker) { - function validate(props, propName, componentName, location, propFullName) { - if (typeof typeChecker !== 'function') { - return new PropTypeError( - `Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.`, - ); - } - var propValue = props[propName]; - if (!Array.isArray(propValue)) { - var propType = getPropType(propValue); - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of type ` + - `\`${propType}\` supplied to \`${componentName}\`, expected an array.`, - ); - } - for (var i = 0; i < propValue.length; i++) { - var error = typeChecker( - propValue, - i, - componentName, - location, - `${propFullName}[${i}]`, - ReactPropTypesSecret, - ); - if (error instanceof Error) { - return error; - } - } - return null; - } - return createChainableTypeChecker(validate); -} - -function createElementTypeChecker() { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - if (!ReactElement.isValidElement(propValue)) { - var propType = getPropType(propValue); - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of type ` + - `\`${propType}\` supplied to \`${componentName}\`, expected a single ReactElement.`, - ); - } - return null; - } - return createChainableTypeChecker(validate); -} - -function createInstanceTypeChecker(expectedClass) { - function validate(props, propName, componentName, location, propFullName) { - if (!(props[propName] instanceof expectedClass)) { - var expectedClassName = expectedClass.name || ANONYMOUS; - var actualClassName = getClassName(props[propName]); - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of type ` + - `\`${actualClassName}\` supplied to \`${componentName}\`, expected ` + - `instance of \`${expectedClassName}\`.`, - ); - } - return null; - } - return createChainableTypeChecker(validate); -} - -function createEnumTypeChecker(expectedValues) { - if (!Array.isArray(expectedValues)) { - warning( - false, - 'Invalid argument supplied to oneOf, expected an instance of array.', - ); - return emptyFunction.thatReturnsNull; - } - - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - for (var i = 0; i < expectedValues.length; i++) { - if (is(propValue, expectedValues[i])) { - return null; - } - } - - var valuesString = JSON.stringify(expectedValues); - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of value \`${propValue}\` ` + - `supplied to \`${componentName}\`, expected one of ${valuesString}.`, - ); - } - return createChainableTypeChecker(validate); -} - -function createObjectOfTypeChecker(typeChecker) { - function validate(props, propName, componentName, location, propFullName) { - if (typeof typeChecker !== 'function') { - return new PropTypeError( - `Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.`, - ); - } - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of type ` + - `\`${propType}\` supplied to \`${componentName}\`, expected an object.`, - ); - } - for (var key in propValue) { - if (propValue.hasOwnProperty(key)) { - var error = typeChecker( - propValue, - key, - componentName, - location, - `${propFullName}.${key}`, - ReactPropTypesSecret, - ); - if (error instanceof Error) { - return error; - } - } - } - return null; - } - return createChainableTypeChecker(validate); -} - -function createUnionTypeChecker(arrayOfTypeCheckers) { - if (!Array.isArray(arrayOfTypeCheckers)) { - warning( - false, - 'Invalid argument supplied to oneOfType, expected an instance of array.', - ); - return emptyFunction.thatReturnsNull; - } - - function validate(props, propName, componentName, location, propFullName) { - for (var i = 0; i < arrayOfTypeCheckers.length; i++) { - var checker = arrayOfTypeCheckers[i]; - if ( - checker( - props, - propName, - componentName, - location, - propFullName, - ReactPropTypesSecret, - ) == null - ) { - return null; - } - } - - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` supplied to ` + - `\`${componentName}\`.`, - ); - } - return createChainableTypeChecker(validate); -} - -function createNodeChecker() { - function validate(props, propName, componentName, location, propFullName) { - if (!isNode(props[propName])) { - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` supplied to ` + - `\`${componentName}\`, expected a ReactNode.`, - ); - } - return null; - } - return createChainableTypeChecker(validate); -} - -function createShapeTypeChecker(shapeTypes) { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError( - `Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` + - `supplied to \`${componentName}\`, expected \`object\`.`, - ); - } - for (var key in shapeTypes) { - var checker = shapeTypes[key]; - if (!checker) { - continue; - } - var error = checker( - propValue, - key, - componentName, - location, - `${propFullName}.${key}`, - ReactPropTypesSecret, - ); - if (error) { - return error; - } - } - return null; - } - return createChainableTypeChecker(validate); -} - -function isNode(propValue) { - switch (typeof propValue) { - case 'number': - case 'string': - case 'undefined': - return true; - case 'boolean': - return !propValue; - case 'object': - if (Array.isArray(propValue)) { - return propValue.every(isNode); - } - if (propValue === null || ReactElement.isValidElement(propValue)) { - return true; - } - - var iteratorFn = getIteratorFn(propValue); - if (iteratorFn) { - var iterator = iteratorFn.call(propValue); - var step; - if (iteratorFn !== propValue.entries) { - while (!(step = iterator.next()).done) { - if (!isNode(step.value)) { - return false; - } - } - } else { - // Iterator will provide entry [k,v] tuples rather than values. - while (!(step = iterator.next()).done) { - var entry = step.value; - if (entry) { - if (!isNode(entry[1])) { - return false; - } - } - } - } - } else { - return false; - } - - return true; - default: - return false; - } -} - -function isSymbol(propType, propValue) { - // Native Symbol. - if (propType === 'symbol') { - return true; - } - - // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' - if (propValue['@@toStringTag'] === 'Symbol') { - return true; - } - - // Fallback for non-spec compliant Symbols which are polyfilled. - if (typeof Symbol === 'function' && propValue instanceof Symbol) { - return true; - } - - return false; -} - -// Equivalent of `typeof` but with special handling for array and regexp. -function getPropType(propValue) { - var propType = typeof propValue; - if (Array.isArray(propValue)) { - return 'array'; - } - if (propValue instanceof RegExp) { - // Old webkits (at least until Android 4.0) return 'function' rather than - // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ - // passes PropTypes.object. - return 'object'; - } - if (isSymbol(propType, propValue)) { - return 'symbol'; - } - return propType; -} - -// This handles more types than `getPropType`. Only used for error messages. -// See `createPrimitiveTypeChecker`. -function getPreciseType(propValue) { - var propType = getPropType(propValue); - if (propType === 'object') { - if (propValue instanceof Date) { - return 'date'; - } else if (propValue instanceof RegExp) { - return 'regexp'; - } - } - return propType; -} - -// Returns class name of the object, if any. -function getClassName(propValue) { - if (!propValue.constructor || !propValue.constructor.name) { - return ANONYMOUS; - } - return propValue.constructor.name; -} - -module.exports = ReactPropTypes; +module.exports = factory(isValidElement); diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js deleted file mode 100644 index 33ccb85bd86a7..0000000000000 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ /dev/null @@ -1,219 +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('ReactPropTypesProduction', function() { - var PropTypes; - var React; - var ReactTestUtils; - var oldProcess; - - beforeEach(function() { - __DEV__ = false; - - // Mutating process.env.NODE_ENV would cause our babel plugins to do the - // wrong thing. If you change this, make sure to test with jest --no-cache. - oldProcess = process; - global.process = { - ...process, - env: {...process.env, NODE_ENV: 'production'}, - }; - - jest.resetModules(); - PropTypes = require('ReactPropTypes'); - React = require('react'); - ReactTestUtils = require('ReactTestUtils'); - }); - - afterEach(function() { - __DEV__ = true; - global.process = oldProcess; - }); - - function expectThrowsInProduction(declaration, value) { - var props = {testProp: value}; - expect(() => { - declaration(props, 'testProp', 'testComponent', 'prop'); - }).toThrowError('Minified React error #144'); - } - - describe('Primitive Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.array, /please/); - expectThrowsInProduction(PropTypes.array.isRequired, /please/); - expectThrowsInProduction(PropTypes.array.isRequired, null); - expectThrowsInProduction(PropTypes.array.isRequired, undefined); - expectThrowsInProduction(PropTypes.bool, []); - expectThrowsInProduction(PropTypes.bool.isRequired, []); - expectThrowsInProduction(PropTypes.bool.isRequired, null); - expectThrowsInProduction(PropTypes.bool.isRequired, undefined); - expectThrowsInProduction(PropTypes.func, false); - expectThrowsInProduction(PropTypes.func.isRequired, false); - expectThrowsInProduction(PropTypes.func.isRequired, null); - expectThrowsInProduction(PropTypes.func.isRequired, undefined); - expectThrowsInProduction(PropTypes.number, function() {}); - expectThrowsInProduction(PropTypes.number.isRequired, function() {}); - expectThrowsInProduction(PropTypes.number.isRequired, null); - expectThrowsInProduction(PropTypes.number.isRequired, undefined); - expectThrowsInProduction(PropTypes.string, 0); - expectThrowsInProduction(PropTypes.string.isRequired, 0); - expectThrowsInProduction(PropTypes.string.isRequired, null); - expectThrowsInProduction(PropTypes.string.isRequired, undefined); - expectThrowsInProduction(PropTypes.symbol, 0); - expectThrowsInProduction(PropTypes.symbol.isRequired, 0); - expectThrowsInProduction(PropTypes.symbol.isRequired, null); - expectThrowsInProduction(PropTypes.symbol.isRequired, undefined); - expectThrowsInProduction(PropTypes.object, ''); - expectThrowsInProduction(PropTypes.object.isRequired, ''); - expectThrowsInProduction(PropTypes.object.isRequired, null); - expectThrowsInProduction(PropTypes.object.isRequired, undefined); - }); - }); - - describe('Any Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.any, null); - expectThrowsInProduction(PropTypes.any.isRequired, null); - expectThrowsInProduction(PropTypes.any.isRequired, undefined); - }); - }); - - describe('ArrayOf Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.arrayOf({foo: PropTypes.string}), { - foo: 'bar', - }); - expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), [ - 1, - 2, - 'b', - ]); - expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), { - '0': 'maybe-array', - length: 1, - }); - expectThrowsInProduction( - PropTypes.arrayOf(PropTypes.number).isRequired, - null, - ); - expectThrowsInProduction( - PropTypes.arrayOf(PropTypes.number).isRequired, - undefined, - ); - }); - }); - - describe('Component Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.element, [
    ,
    ]); - expectThrowsInProduction(PropTypes.element, 123); - expectThrowsInProduction(PropTypes.element, 'foo'); - expectThrowsInProduction(PropTypes.element, false); - expectThrowsInProduction(PropTypes.element.isRequired, null); - expectThrowsInProduction(PropTypes.element.isRequired, undefined); - }); - }); - - describe('Instance Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.instanceOf(Date), {}); - expectThrowsInProduction(PropTypes.instanceOf(Date).isRequired, {}); - }); - }); - - describe('React Component Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.node, {}); - expectThrowsInProduction(PropTypes.node.isRequired, null); - expectThrowsInProduction(PropTypes.node.isRequired, undefined); - }); - }); - - describe('ObjectOf Type', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.objectOf({foo: PropTypes.string}), { - foo: 'bar', - }); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), { - a: 1, - b: 2, - c: 'b', - }); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), [1, 2]); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), null); - expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), undefined); - }); - }); - - describe('OneOf Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.oneOf('red', 'blue'), 'red'); - expectThrowsInProduction(PropTypes.oneOf(['red', 'blue']), true); - expectThrowsInProduction(PropTypes.oneOf(['red', 'blue']), null); - expectThrowsInProduction(PropTypes.oneOf(['red', 'blue']), undefined); - }); - }); - - describe('Union Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction( - PropTypes.oneOfType(PropTypes.string, PropTypes.number), - 'red', - ); - expectThrowsInProduction( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - [], - ); - expectThrowsInProduction( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - null, - ); - expectThrowsInProduction( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - undefined, - ); - }); - }); - - describe('Shape Types', function() { - it('should be a no-op', function() { - expectThrowsInProduction(PropTypes.shape({}), 'some string'); - expectThrowsInProduction( - PropTypes.shape({key: PropTypes.number}).isRequired, - null, - ); - expectThrowsInProduction( - PropTypes.shape({key: PropTypes.number}).isRequired, - undefined, - ); - }); - }); - - describe('Custom validator', function() { - beforeEach(function() { - jest.resetModules(); - }); - - it('should not have been called', function() { - var spy = jest.fn(); - function Component() { - return
    ; - } - Component.propTypes = {num: spy}; - - var instance = ; - ReactTestUtils.renderIntoDocument(instance); - - expect(spy).not.toBeCalled(); - }); - }); -}); diff --git a/src/isomorphic/classic/types/checkPropTypes.js b/src/isomorphic/classic/types/checkPropTypes.js index 5168efd9c001f..32d9ecc677497 100644 --- a/src/isomorphic/classic/types/checkPropTypes.js +++ b/src/isomorphic/classic/types/checkPropTypes.js @@ -11,84 +11,4 @@ 'use strict'; -var ReactPropTypesSecret = require('ReactPropTypesSecret'); - -var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); - -var loggedTypeFailures = {}; - -/** - * Assert that the values match with the type specs. - * Error messages are memorized and will only be shown once. - * - * @param {object} typeSpecs Map of name to a ReactPropType - * @param {object} values Runtime values that need to be type-checked - * @param {string} location e.g. "prop", "context", "child context" - * @param {string} componentName Name of the component for error messages. - * @param {?Function} getStack Returns the component stack. - * @private - */ -function checkPropTypes(typeSpecs, values, location, componentName, getStack) { - if (__DEV__) { - for (var typeSpecName in typeSpecs) { - if (typeSpecs.hasOwnProperty(typeSpecName)) { - var error; - // Prop type validation may throw. In case they do, we don't want to - // fail the render phase where it didn't fail before. So we log it. - // After these have been cleaned up, we'll let them throw. - try { - // This is intentionally an invariant that gets caught. It's the same - // behavior as without this statement except with a better message. - invariant( - typeof typeSpecs[typeSpecName] === 'function', - '%s: %s type `%s` is invalid; it must be a function, usually from ' + - 'React.PropTypes.', - componentName || 'React class', - location, - typeSpecName, - ); - error = typeSpecs[typeSpecName]( - values, - typeSpecName, - componentName, - location, - null, - ReactPropTypesSecret, - ); - } catch (ex) { - error = ex; - } - warning( - !error || error instanceof Error, - '%s: type specification of %s `%s` is invalid; the type checker ' + - 'function must return `null` or an `Error` but returned a %s. ' + - 'You may have forgotten to pass an argument to the type checker ' + - 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + - 'shape all require an argument).', - componentName || 'React class', - location, - typeSpecName, - typeof error, - ); - if (error instanceof Error && !(error.message in loggedTypeFailures)) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures[error.message] = true; - - var stack = getStack ? getStack() : ''; - - warning( - false, - 'Failed %s type: %s%s', - location, - error.message, - stack != null ? stack : '', - ); - } - } - } - } -} - -module.exports = checkPropTypes; +module.exports = require('prop-types/checkPropTypes'); diff --git a/src/isomorphic/modern/class/PropTypes.d.ts b/src/isomorphic/modern/class/PropTypes.d.ts new file mode 100644 index 0000000000000..a8802e66fe859 --- /dev/null +++ b/src/isomorphic/modern/class/PropTypes.d.ts @@ -0,0 +1,19 @@ +/*! + * 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. + */ + +/** + * TypeScript Definition File for React. + * + * Full type definitions are not yet officially supported. These are mostly + * just helpers for the unit test. + */ + +declare module 'prop-types' { + export var string : any; +} diff --git a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee index 1880a3dc6efaf..15f5e46eab758 100644 --- a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee @@ -9,6 +9,7 @@ of patent rights can be found in the PATENTS file in the same directory. React = null ReactDOM = null +PropTypes = null describe 'ReactCoffeeScriptClass', -> div = null @@ -21,6 +22,7 @@ describe 'ReactCoffeeScriptClass', -> beforeEach -> React = require 'react' ReactDOM = require 'react-dom' + PropTypes = require 'prop-types' container = document.createElement 'div' attachedListener = null renderedName = null @@ -102,8 +104,8 @@ describe 'ReactCoffeeScriptClass', -> it 'renders based on context in the constructor', -> class Foo extends React.Component @contextTypes: - tag: React.PropTypes.string - className: React.PropTypes.string + tag: PropTypes.string + className: PropTypes.string constructor: (props, context) -> super props, context @@ -118,8 +120,8 @@ describe 'ReactCoffeeScriptClass', -> class Outer extends React.Component @childContextTypes: - tag: React.PropTypes.string - className: React.PropTypes.string + tag: PropTypes.string + className: PropTypes.string getChildContext: -> tag: 'span' @@ -393,13 +395,13 @@ describe 'ReactCoffeeScriptClass', -> it 'supports this.context passed via getChildContext', -> class Bar extends React.Component @contextTypes: - bar: React.PropTypes.string + bar: PropTypes.string render: -> div className: @context.bar class Foo extends React.Component @childContextTypes: - bar: React.PropTypes.string + bar: PropTypes.string getChildContext: -> bar: 'bar-through-context' render: -> diff --git a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js index a6ec313d5c105..f634e1d1c58d4 100644 --- a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js +++ b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactDOM; @@ -25,6 +26,7 @@ describe('ReactES6Class', () => { var renderedName = null; beforeEach(() => { + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); container = document.createElement('div'); @@ -123,8 +125,8 @@ describe('ReactES6Class', () => { } } Foo.contextTypes = { - tag: React.PropTypes.string, - className: React.PropTypes.string, + tag: PropTypes.string, + className: PropTypes.string, }; class Outer extends React.Component { @@ -136,8 +138,8 @@ describe('ReactES6Class', () => { } } Outer.childContextTypes = { - tag: React.PropTypes.string, - className: React.PropTypes.string, + tag: PropTypes.string, + className: PropTypes.string, }; test(, 'SPAN', 'foo'); }); @@ -419,7 +421,7 @@ describe('ReactES6Class', () => { return
    ; } } - Bar.contextTypes = {bar: React.PropTypes.string}; + Bar.contextTypes = {bar: PropTypes.string}; class Foo extends React.Component { getChildContext() { return {bar: 'bar-through-context'}; @@ -428,7 +430,7 @@ describe('ReactES6Class', () => { return ; } } - Foo.childContextTypes = {bar: React.PropTypes.string}; + Foo.childContextTypes = {bar: PropTypes.string}; test(, 'DIV', 'bar-through-context'); }); diff --git a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts index 921474d3affbc..33085c89d9213 100644 --- a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts +++ b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts @@ -1,3 +1,4 @@ +/// /// /// @@ -12,6 +13,7 @@ import React = require('react'); import ReactDOM = require('react-dom'); +import PropTypes = require('prop-types'); // Before Each @@ -85,8 +87,8 @@ class StateBasedOnProps extends React.Component { // it renders based on context in the constructor class StateBasedOnContext extends React.Component { static contextTypes = { - tag: React.PropTypes.string, - className: React.PropTypes.string + tag: PropTypes.string, + className: PropTypes.string }; state = { tag: this.context.tag, @@ -100,8 +102,8 @@ class StateBasedOnContext extends React.Component { class ProvideChildContextTypes extends React.Component { static childContextTypes = { - tag: React.PropTypes.string, - className: React.PropTypes.string + tag: PropTypes.string, + className: PropTypes.string }; getChildContext() { return { tag: 'span', className: 'foo' }; @@ -278,13 +280,13 @@ class MisspelledComponent2 extends React.Component { // it supports this.context passed via getChildContext class ReadContext extends React.Component { - static contextTypes = { bar: React.PropTypes.string }; + static contextTypes = { bar: PropTypes.string }; render() { return React.createElement('div', { className: this.context.bar }); } } class ProvideContext extends React.Component { - static childContextTypes = { bar: React.PropTypes.string }; + static childContextTypes = { bar: PropTypes.string }; getChildContext() { return { bar: 'bar-through-context' }; } diff --git a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js index 5074097dfa47f..ff1ff2e7c8e6d 100644 --- a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js +++ b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js @@ -17,6 +17,7 @@ var React; var ReactDOM; var ReactTestUtils; +var PropTypes; describe('ReactJSXElementValidator', () => { function normalizeCodeLocInfo(str) { @@ -29,6 +30,7 @@ describe('ReactJSXElementValidator', () => { beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); @@ -45,7 +47,7 @@ describe('ReactJSXElementValidator', () => { } }; RequiredPropComponent.displayName = 'RequiredPropComponent'; - RequiredPropComponent.propTypes = {prop: React.PropTypes.string.isRequired}; + RequiredPropComponent.propTypes = {prop: PropTypes.string.isRequired}; }); it('warns for keys for arrays of elements in children position', () => { @@ -188,7 +190,7 @@ describe('ReactJSXElementValidator', () => { } } MyComp.propTypes = { - color: React.PropTypes.string, + color: PropTypes.string, }; class ParentComp extends React.Component { render() { @@ -211,7 +213,7 @@ describe('ReactJSXElementValidator', () => { return null; } MyComp.propTypes = { - color: React.PropTypes.string, + color: PropTypes.string, }; function MiddleComp(props) { return ; diff --git a/src/renderers/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/__tests__/ReactComponentLifeCycle-test.js index b9231571bb733..af575d153071c 100644 --- a/src/renderers/__tests__/ReactComponentLifeCycle-test.js +++ b/src/renderers/__tests__/ReactComponentLifeCycle-test.js @@ -14,6 +14,7 @@ var React; var ReactDOM; var ReactTestUtils; +var PropTypes; var clone = function(o) { return JSON.parse(JSON.stringify(o)); @@ -91,6 +92,7 @@ describe('ReactComponentLifeCycle', () => { React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); + PropTypes = require('prop-types'); }); it('should not reuse an instance when it has been unmounted', () => { @@ -605,14 +607,14 @@ describe('ReactComponentLifeCycle', () => { }; } Parent.childContextTypes = { - x: React.PropTypes.number, + x: PropTypes.number, }; function Child(props, context) { expect(context.x).toBe(2); return
    ; } Child.contextTypes = { - x: React.PropTypes.number, + x: PropTypes.number, }; const div = document.createElement('div'); diff --git a/src/renderers/__tests__/ReactComponentTreeHook-test.native.js b/src/renderers/__tests__/ReactComponentTreeHook-test.native.js index dd7be7d7014ce..ff458d64a4d6d 100644 --- a/src/renderers/__tests__/ReactComponentTreeHook-test.native.js +++ b/src/renderers/__tests__/ReactComponentTreeHook-test.native.js @@ -29,10 +29,12 @@ describeStack('ReactComponentTreeHook', () => { var View; var Image; var Text; + var PropTypes; beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); React = require('react'); ReactNative = require('ReactNative'); ReactInstanceMap = require('ReactInstanceMap'); @@ -50,7 +52,7 @@ describeStack('ReactComponentTreeHook', () => { }); Text = class extends React.Component { static childContextTypes = { - isInAParentText: React.PropTypes.bool, + isInAParentText: PropTypes.bool, }; getChildContext() { diff --git a/src/renderers/__tests__/ReactErrorBoundaries-test.js b/src/renderers/__tests__/ReactErrorBoundaries-test.js index d9a34dc5e6f84..49e9a1273dc28 100644 --- a/src/renderers/__tests__/ReactErrorBoundaries-test.js +++ b/src/renderers/__tests__/ReactErrorBoundaries-test.js @@ -13,6 +13,7 @@ var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); +var PropTypes; var React; var ReactDOM; @@ -37,6 +38,7 @@ describe('ReactErrorBoundaries', () => { var Normal; beforeEach(() => { + PropTypes = require('prop-types'); ReactDOM = require('react-dom'); React = require('react'); @@ -737,7 +739,7 @@ describe('ReactErrorBoundaries', () => { it('renders an error state if context provider throws in componentWillMount', () => { class BrokenComponentWillMountWithContext extends React.Component { - static childContextTypes = {foo: React.PropTypes.number}; + static childContextTypes = {foo: PropTypes.number}; getChildContext() { return {foo: 42}; } @@ -774,7 +776,7 @@ describe('ReactErrorBoundaries', () => { }; } BrokenComponentWillMountWithContext.childContextTypes = { - foo: React.PropTypes.number, + foo: PropTypes.number, }; var container = document.createElement('div'); diff --git a/src/renderers/__tests__/ReactStatelessComponent-test.js b/src/renderers/__tests__/ReactStatelessComponent-test.js index 3f11bf438e15e..0792eded59464 100644 --- a/src/renderers/__tests__/ReactStatelessComponent-test.js +++ b/src/renderers/__tests__/ReactStatelessComponent-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactDOM; var ReactTestUtils; @@ -28,6 +29,7 @@ describe('ReactStatelessComponent', () => { beforeEach(() => { jest.resetModuleRegistry(); + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('ReactTestUtils'); @@ -68,7 +70,7 @@ describe('ReactStatelessComponent', () => { it('should pass context thru stateless component', () => { class Child extends React.Component { static contextTypes = { - test: React.PropTypes.string.isRequired, + test: PropTypes.string.isRequired, }; render() { @@ -82,7 +84,7 @@ describe('ReactStatelessComponent', () => { class GrandParent extends React.Component { static childContextTypes = { - test: React.PropTypes.string.isRequired, + test: PropTypes.string.isRequired, }; getChildContext() { @@ -111,7 +113,7 @@ describe('ReactStatelessComponent', () => { } StatelessComponentWithChildContext.childContextTypes = { - foo: React.PropTypes.string, + foo: PropTypes.string, }; var container = document.createElement('div'); @@ -355,7 +357,7 @@ describe('ReactStatelessComponent', () => { return
    {props.test}
    ; } Child.defaultProps = {test: 2}; - Child.propTypes = {test: React.PropTypes.string}; + Child.propTypes = {test: PropTypes.string}; spyOn(console, 'error'); ReactTestUtils.renderIntoDocument(); @@ -372,7 +374,7 @@ describe('ReactStatelessComponent', () => { it('should receive context', () => { class Parent extends React.Component { static childContextTypes = { - lang: React.PropTypes.string, + lang: PropTypes.string, }; getChildContext() { @@ -387,7 +389,7 @@ describe('ReactStatelessComponent', () => { function Child(props, context) { return
    {context.lang}
    ; } - Child.contextTypes = {lang: React.PropTypes.string}; + Child.contextTypes = {lang: PropTypes.string}; var el = document.createElement('div'); ReactDOM.render(, el); diff --git a/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js b/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js index a2280be28f1f2..026fa910355a5 100644 --- a/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js +++ b/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js @@ -15,6 +15,7 @@ var React = require('react'); var ReactDOM = require('react-dom'); var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); var ReactTestUtils = require('ReactTestUtils'); +var PropTypes = require('prop-types'); describe('ReactDOMFiber', () => { var container; @@ -683,7 +684,7 @@ describe('ReactDOMFiber', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; render() { @@ -693,7 +694,7 @@ describe('ReactDOMFiber', () => { class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; getChildContext() { @@ -717,8 +718,8 @@ describe('ReactDOMFiber', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; render() { @@ -728,8 +729,8 @@ describe('ReactDOMFiber', () => { class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; state = { @@ -761,8 +762,8 @@ describe('ReactDOMFiber', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; render() { @@ -772,8 +773,8 @@ describe('ReactDOMFiber', () => { class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; getChildContext() { diff --git a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js index af29b8d5ac882..0381ec8fb82aa 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js @@ -12,6 +12,7 @@ 'use strict'; let ExecutionEnvironment; +let PropTypes; let React; let ReactDOM; let ReactDOMServer; @@ -206,6 +207,7 @@ function expectMarkupMismatch(serverElement, clientElement) { // To get around this, we must reload React modules in between server and client render. function resetModules() { jest.resetModuleRegistry(); + PropTypes = require('prop-types'); React = require('React'); ReactDOM = require('ReactDOM'); ReactDOMServer = require('ReactDOMServer'); @@ -1585,7 +1587,7 @@ describe('ReactDOMServerIntegration', () => { return this.props.children; } } - Parent.childContextTypes = {text: React.PropTypes.string}; + Parent.childContextTypes = {text: PropTypes.string}; PurpleContext = props => {props.children}; RedContext = props => {props.children}; @@ -1597,7 +1599,7 @@ describe('ReactDOMServerIntegration', () => { return
    {this.context.text}
    ; } } - ClassChildWithContext.contextTypes = {text: React.PropTypes.string}; + ClassChildWithContext.contextTypes = {text: PropTypes.string}; const e = await render( , @@ -1609,7 +1611,7 @@ describe('ReactDOMServerIntegration', () => { function StatelessChildWithContext(props, context) { return
    {context.text}
    ; } - StatelessChildWithContext.contextTypes = {text: React.PropTypes.string}; + StatelessChildWithContext.contextTypes = {text: PropTypes.string}; const e = await render( , @@ -1650,7 +1652,7 @@ describe('ReactDOMServerIntegration', () => { return
    {this.context.text}
    ; } } - ClassChildWithWrongContext.contextTypes = {foo: React.PropTypes.string}; + ClassChildWithWrongContext.contextTypes = {foo: PropTypes.string}; const e = await render( , @@ -1664,7 +1666,7 @@ describe('ReactDOMServerIntegration', () => { return
    {context.text}
    ; } StatelessChildWithWrongContext.contextTypes = { - foo: React.PropTypes.string, + foo: PropTypes.string, }; const e = await render( @@ -1677,7 +1679,7 @@ describe('ReactDOMServerIntegration', () => { function Grandchild(props, context) { return
    {context.text}
    ; } - Grandchild.contextTypes = {text: React.PropTypes.string}; + Grandchild.contextTypes = {text: PropTypes.string}; const Child = props => ; @@ -1689,7 +1691,7 @@ describe('ReactDOMServerIntegration', () => { const Grandchild = (props, context) => { return
    {context.text}
    ; }; - Grandchild.contextTypes = {text: React.PropTypes.string}; + Grandchild.contextTypes = {text: PropTypes.string}; const e = await render( , @@ -1706,7 +1708,7 @@ describe('ReactDOMServerIntegration', () => { return ; } } - Parent.childContextTypes = {text1: React.PropTypes.string}; + Parent.childContextTypes = {text1: PropTypes.string}; class Child extends React.Component { getChildContext() { @@ -1716,7 +1718,7 @@ describe('ReactDOMServerIntegration', () => { return ; } } - Child.childContextTypes = {text2: React.PropTypes.string}; + Child.childContextTypes = {text2: PropTypes.string}; const Grandchild = (props, context) => { return ( @@ -1727,8 +1729,8 @@ describe('ReactDOMServerIntegration', () => { ); }; Grandchild.contextTypes = { - text1: React.PropTypes.string, - text2: React.PropTypes.string, + text1: PropTypes.string, + text2: PropTypes.string, }; const e = await render(); @@ -1750,12 +1752,12 @@ describe('ReactDOMServerIntegration', () => { return ; } } - WillMountContext.childContextTypes = {text: React.PropTypes.string}; + WillMountContext.childContextTypes = {text: PropTypes.string}; const Child = (props, context) => { return
    {context.text}
    ; }; - Child.contextTypes = {text: React.PropTypes.string}; + Child.contextTypes = {text: PropTypes.string}; const e = await render(); expect(e.textContent).toBe('foo'); @@ -1788,7 +1790,7 @@ describe('ReactDOMServerIntegration', () => { return {value1: 'foo', value2: 'bar'}; } } - Component.childContextTypes = {value1: React.PropTypes.string}; + Component.childContextTypes = {value1: PropTypes.string}; return render(); }, ); diff --git a/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js b/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js index 30e617480b1fa..a0a30dfe8d726 100644 --- a/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js +++ b/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js @@ -12,6 +12,7 @@ 'use strict'; var React = require('react'); +var PropTypes = require('prop-types'); var ReactDOM = require('react-dom'); var ReactTestUtils = require('ReactTestUtils'); var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer'); @@ -22,7 +23,7 @@ describe('renderSubtreeIntoContainer', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; render() { @@ -32,7 +33,7 @@ describe('renderSubtreeIntoContainer', () => { class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; getChildContext() { @@ -63,7 +64,7 @@ describe('renderSubtreeIntoContainer', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; render() { @@ -76,7 +77,7 @@ describe('renderSubtreeIntoContainer', () => { // eslint-disable-next-line no-unused-vars class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, + foo: PropTypes.string.isRequired, }; getChildContext() { @@ -104,8 +105,8 @@ describe('renderSubtreeIntoContainer', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; render() { @@ -115,8 +116,8 @@ describe('renderSubtreeIntoContainer', () => { class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; state = { @@ -156,8 +157,8 @@ describe('renderSubtreeIntoContainer', () => { class Component extends React.Component { static contextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; render() { @@ -167,8 +168,8 @@ describe('renderSubtreeIntoContainer', () => { class Parent extends React.Component { static childContextTypes = { - foo: React.PropTypes.string.isRequired, - getFoo: React.PropTypes.func.isRequired, + foo: PropTypes.string.isRequired, + getFoo: PropTypes.func.isRequired, }; getChildContext() { @@ -229,7 +230,7 @@ describe('renderSubtreeIntoContainer', () => { return {value: this.props.value}; } static childContextTypes = { - value: React.PropTypes.string.isRequired, + value: PropTypes.string.isRequired, }; } @@ -244,7 +245,7 @@ describe('renderSubtreeIntoContainer', () => { class Child extends React.Component { static contextTypes = { - value: React.PropTypes.string.isRequired, + value: PropTypes.string.isRequired, }; render() { return
    {this.context.value}
    ; @@ -272,7 +273,7 @@ describe('renderSubtreeIntoContainer', () => { renderSubtreeIntoContainer(this, , portal1); } static childContextTypes = { - value: React.PropTypes.string.isRequired, + value: PropTypes.string.isRequired, }; } @@ -287,7 +288,7 @@ describe('renderSubtreeIntoContainer', () => { class Child extends React.Component { static contextTypes = { - value: React.PropTypes.string.isRequired, + value: PropTypes.string.isRequired, }; render() { return
    {this.context.value}
    ; diff --git a/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js b/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js index e0cdedf22f5c7..0f8b44bc81e4d 100644 --- a/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js +++ b/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js @@ -11,7 +11,7 @@ 'use strict'; -var React = require('react'); +var PropTypes = require('prop-types'); var ReactPropTypesSecret = require('ReactPropTypesSecret'); var warning = require('fbjs/lib/warning'); @@ -57,7 +57,7 @@ var propTypes = { 'set either `onChange` or `readOnly`.', ); }, - onChange: React.PropTypes.func, + onChange: PropTypes.func, }; var loggedTypeFailures = {}; diff --git a/src/renderers/native/__tests__/ReactNativeEvents-test.js b/src/renderers/native/__tests__/ReactNativeEvents-test.js index 56206149a75e0..9efa5f05e097b 100644 --- a/src/renderers/native/__tests__/ReactNativeEvents-test.js +++ b/src/renderers/native/__tests__/ReactNativeEvents-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var RCTEventEmitter; var React; var ReactNative; @@ -21,6 +22,7 @@ var createReactNativeComponentClass; beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); RCTEventEmitter = require('RCTEventEmitter'); React = require('react'); ReactNative = require('ReactNative'); @@ -97,7 +99,7 @@ it('handles events on text nodes', () => { }); class ContextHack extends React.Component { - static childContextTypes = {isInAParentText: React.PropTypes.bool}; + static childContextTypes = {isInAParentText: PropTypes.bool}; getChildContext() { return {isInAParentText: true}; } diff --git a/src/renderers/shared/fiber/ReactFiberContext.js b/src/renderers/shared/fiber/ReactFiberContext.js index e60fdd850eb16..b2104d19e9039 100644 --- a/src/renderers/shared/fiber/ReactFiberContext.js +++ b/src/renderers/shared/fiber/ReactFiberContext.js @@ -15,7 +15,7 @@ import type {Fiber} from 'ReactFiber'; import type {StackCursor} from 'ReactFiberStack'; -var React = require('react'); +var checkPropTypes = require('checkPropTypes'); var emptyObject = require('fbjs/lib/emptyObject'); var getComponentName = require('getComponentName'); var invariant = require('fbjs/lib/invariant'); @@ -105,8 +105,7 @@ exports.getMaskedContext = function( if (__DEV__) { const name = getComponentName(workInProgress) || 'Unknown'; ReactDebugCurrentFrame.current = workInProgress; - // $FlowFixMe - We know this export exists now, need to wait for Flow update - React.checkPropTypes( + checkPropTypes( contextTypes, context, 'context', @@ -219,8 +218,7 @@ function processChildContext( // TODO: remove this hack when we delete unstable_renderSubtree in Fiber. const workInProgress = isReconciling ? fiber : null; ReactDebugCurrentFrame.current = workInProgress; - // $FlowFixMe - We know this export exists now, need to wait for Flow update - React.checkPropTypes( + checkPropTypes( childContextTypes, childContext, 'child context', diff --git a/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js index f0da503be5e12..b66151f38e2aa 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js @@ -14,12 +14,14 @@ var React; var ReactNoop; var ReactFeatureFlags; +var PropTypes; describe('ReactIncremental', () => { beforeEach(() => { jest.resetModules(); React = require('react'); ReactNoop = require('ReactNoop'); + PropTypes = require('prop-types'); ReactFeatureFlags = require('ReactFeatureFlags'); ReactFeatureFlags.disableNewFiberFeatures = false; @@ -1592,7 +1594,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { return { @@ -1607,7 +1609,7 @@ describe('ReactIncremental', () => { class Router extends React.Component { static childContextTypes = { - route: React.PropTypes.string, + route: PropTypes.string, }; getChildContext() { return { @@ -1622,7 +1624,7 @@ describe('ReactIncremental', () => { class ShowLocale extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocale ' + JSON.stringify(this.context)); @@ -1632,7 +1634,7 @@ describe('ReactIncremental', () => { class ShowRoute extends React.Component { static contextTypes = { - route: React.PropTypes.string, + route: PropTypes.string, }; render() { ops.push('ShowRoute ' + JSON.stringify(this.context)); @@ -1645,8 +1647,8 @@ describe('ReactIncremental', () => { return `${context.route} in ${context.locale}`; } ShowBoth.contextTypes = { - locale: React.PropTypes.string, - route: React.PropTypes.string, + locale: PropTypes.string, + route: PropTypes.string, }; class ShowNeither extends React.Component { @@ -1745,10 +1747,10 @@ describe('ReactIncremental', () => { var ops = []; class Recurse extends React.Component { static contextTypes = { - n: React.PropTypes.number, + n: PropTypes.number, }; static childContextTypes = { - n: React.PropTypes.number, + n: PropTypes.number, }; getChildContext() { return {n: (this.context.n || 3) - 1}; @@ -1777,7 +1779,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { return { @@ -1792,7 +1794,7 @@ describe('ReactIncremental', () => { class ShowLocale extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocale ' + JSON.stringify(this.context)); @@ -1835,7 +1837,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { const childContext = { @@ -1852,7 +1854,7 @@ describe('ReactIncremental', () => { class ShowLocaleClass extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocaleClass:read ' + JSON.stringify(this.context)); @@ -1865,7 +1867,7 @@ describe('ReactIncremental', () => { return context.locale; } ShowLocaleFn.contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; class Stateful extends React.Component { @@ -1925,7 +1927,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { const childContext = { @@ -1942,7 +1944,7 @@ describe('ReactIncremental', () => { class ShowLocaleClass extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocaleClass:read ' + JSON.stringify(this.context)); @@ -1955,7 +1957,7 @@ describe('ReactIncremental', () => { return context.locale; } ShowLocaleFn.contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; function IndirectionFn(props, context) { diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js index 4b4b415cc7173..b4c9098e8f4cf 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactNoop; var ReactFeatureFlags; @@ -18,6 +19,7 @@ var ReactFeatureFlags; describe('ReactIncrementalErrorHandling', () => { beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); React = require('react'); ReactNoop = require('ReactNoop'); ReactFeatureFlags = require('ReactFeatureFlags'); @@ -679,8 +681,8 @@ describe('ReactIncrementalErrorHandling', () => { it('unwinds the context stack correctly on error', () => { class Provider extends React.Component { - static childContextTypes = {message: React.PropTypes.string}; - static contextTypes = {message: React.PropTypes.string}; + static childContextTypes = {message: PropTypes.string}; + static contextTypes = {message: PropTypes.string}; getChildContext() { return { message: (this.context.message || '') + this.props.message, @@ -696,7 +698,7 @@ describe('ReactIncrementalErrorHandling', () => { } Connector.contextTypes = { - message: React.PropTypes.string, + message: PropTypes.string, }; function BadRender() { diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js index b4a47480039fd..56fa122245c1d 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js @@ -17,6 +17,7 @@ describe('ReactDebugFiberPerf', () => { let ReactFeatureFlags; let ReactNoop; let ReactPortal; + let PropTypes; let root; let activeMeasure; @@ -119,6 +120,7 @@ describe('ReactDebugFiberPerf', () => { ReactNoop = require('ReactNoop'); ReactPortal = require('ReactPortal'); ReactFeatureFlags.disableNewFiberFeatures = false; + PropTypes = require('prop-types'); }); afterEach(() => { @@ -245,7 +247,7 @@ describe('ReactDebugFiberPerf', () => { it('captures all lifecycles', () => { class AllLifecycles extends React.Component { static childContextTypes = { - foo: React.PropTypes.any, + foo: PropTypes.any, }; shouldComponentUpdate() { return true; diff --git a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js index 6649dffaf64b5..2ad0d4b40316b 100644 --- a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js @@ -27,6 +27,7 @@ if (__DEV__) { var warningAboutMissingGetChildContext = {}; } +var checkPropTypes = require('checkPropTypes'); var emptyObject = require('fbjs/lib/emptyObject'); var invariant = require('fbjs/lib/invariant'); var shallowEqual = require('fbjs/lib/shallowEqual'); @@ -729,7 +730,7 @@ var ReactCompositeComponent = { _checkContextTypes: function(typeSpecs, values, location: string) { if (__DEV__) { ReactDebugCurrentFrame.current = this._debugID; - React.checkPropTypes( + checkPropTypes( typeSpecs, values, location, diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js index 68c489cfb8f3d..cd1b2a5dc8a5c 100644 --- a/src/test/__tests__/ReactTestUtils-test.js +++ b/src/test/__tests__/ReactTestUtils-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactDOM; var ReactDOMServer; @@ -18,6 +19,7 @@ var ReactTestUtils; describe('ReactTestUtils', () => { beforeEach(() => { + PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactDOMServer = require('react-dom/server'); @@ -195,7 +197,7 @@ describe('ReactTestUtils', () => { it('can shallowly render components with contextTypes', () => { class SimpleComponent extends React.Component { static contextTypes = { - name: React.PropTypes.string, + name: PropTypes.string, }; render() { @@ -258,7 +260,7 @@ describe('ReactTestUtils', () => { it('can pass context when shallowly rendering', () => { class SimpleComponent extends React.Component { static contextTypes = { - name: React.PropTypes.string, + name: PropTypes.string, }; render() { @@ -278,7 +280,7 @@ describe('ReactTestUtils', () => { class SimpleComponent extends React.Component { static contextTypes = { - name: React.PropTypes.string.isRequired, + name: PropTypes.string.isRequired, }; render() { diff --git a/yarn.lock b/yarn.lock index 681679cb60642..bd8f7924ce013 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1438,11 +1438,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2: create-hash "^1.1.0" inherits "^2.0.1" -create-react-class@^15.5.0: - version "15.5.0" - resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.0.tgz#7508ffcad56a0804fb244d6ff70b07648abfe5fb" +create-react-class@^15.5.2: + version "15.5.2" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.2.tgz#6a8758348df660b88326a0e764d569f274aad681" dependencies: fbjs "^0.8.9" + object-assign "^4.1.1" cross-spawn-async@^2.2.2: version "2.2.5" @@ -3929,6 +3930,12 @@ promise@^7.1.1: dependencies: asap "~2.0.3" +prop-types@^15.5.6: + version "15.5.6" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.6.tgz#797a915b1714b645ebb7c5d6cc690346205bd2aa" + dependencies: + fbjs "^0.8.9" + prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" From 6cd7618bd7ed5a52aaf576a3fe5fb71f594c38a1 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 11 Apr 2017 14:40:56 -0700 Subject: [PATCH 24/43] Bumped versions for 16.0.0-alpha.9 and re-built --- package.json | 2 +- packages/react-art/package.json | 4 +- packages/react-dom/package.json | 4 +- packages/react-noop-renderer/package.json | 2 +- packages/react-test-renderer/package.json | 4 +- packages/react/package.json | 2 +- scripts/rollup/results.json | 56 +++++++++++------------ src/ReactVersion.js | 2 +- 8 files changed, 38 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index c8c55229203dc..7dba9499b1739 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-build", "private": true, - "version": "16.0.0-alpha.8", + "version": "16.0.0-alpha.9", "devDependencies": { "aliasify": "^2.0.0", "art": "^0.10.1", diff --git a/packages/react-art/package.json b/packages/react-art/package.json index 8f9ddca085cd5..5f14174fa795e 100644 --- a/packages/react-art/package.json +++ b/packages/react-art/package.json @@ -1,6 +1,6 @@ { "name": "react-art", - "version": "16.0.0-alpha.8", + "version": "16.0.0-alpha.9", "description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).", "main": "index.js", "repository": "facebook/react", @@ -23,7 +23,7 @@ "object-assign": "^4.1.0" }, "peerDependencies": { - "react": "^16.0.0-alpha.8" + "react": "^16.0.0-alpha.9" }, "files": [ "LICENSE", diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json index 0dae9585dfe72..52070cd964734 100644 --- a/packages/react-dom/package.json +++ b/packages/react-dom/package.json @@ -1,6 +1,6 @@ { "name": "react-dom", - "version": "16.0.0-alpha.8", + "version": "16.0.0-alpha.9", "description": "React package for working with the DOM.", "main": "index.js", "repository": "facebook/react", @@ -19,7 +19,7 @@ "prop-types": "^15.5.6" }, "peerDependencies": { - "react": "^16.0.0-alpha.8" + "react": "^16.0.0-alpha.9" }, "files": [ "LICENSE", diff --git a/packages/react-noop-renderer/package.json b/packages/react-noop-renderer/package.json index dd0906e193462..bfe1749a0ccf4 100644 --- a/packages/react-noop-renderer/package.json +++ b/packages/react-noop-renderer/package.json @@ -1,6 +1,6 @@ { "name": "react-noop-renderer", - "version": "16.0.0-alpha.8", + "version": "16.0.0-alpha.9", "private": true, "description": "React package for testing the Fiber reconciler.", "main": "index.js", diff --git a/packages/react-test-renderer/package.json b/packages/react-test-renderer/package.json index ef15cc2e25361..a9cedf4ce70d9 100644 --- a/packages/react-test-renderer/package.json +++ b/packages/react-test-renderer/package.json @@ -1,6 +1,6 @@ { "name": "react-test-renderer", - "version": "16.0.0-alpha.8", + "version": "16.0.0-alpha.9", "description": "React package for snapshot testing.", "main": "index.js", "repository": "facebook/react", @@ -19,7 +19,7 @@ "object-assign": "^4.1.0" }, "peerDependencies": { - "react": "^16.0.0-alpha.8" + "react": "^16.0.0-alpha.9" }, "files": [ "LICENSE", diff --git a/packages/react/package.json b/packages/react/package.json index 134466884dc89..4df2dac46893d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,7 +1,7 @@ { "name": "react", "description": "React is a JavaScript library for building user interfaces.", - "version": "16.0.0-alpha.8", + "version": "16.0.0-alpha.9", "keywords": [ "react" ], diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index d676282dc3bff..01bee146eedc6 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -1,21 +1,21 @@ { - "branch": "prop-types", + "branch": "master", "bundleSizes": { "react.development.js (UMD_DEV)": { - "size": 121474, - "gzip": 30524 + "size": 121454, + "gzip": 30515 }, "react.production.min.js (UMD_PROD)": { "size": 15685, "gzip": 5765 }, "react-dom.development.js (UMD_DEV)": { - "size": 583352, - "gzip": 134572 + "size": 583190, + "gzip": 134534 }, "react-dom.production.min.js (UMD_PROD)": { "size": 120740, - "gzip": 38092 + "gzip": 38094 }, "react-dom-server.development.js (UMD_DEV)": { "size": 495558, @@ -26,24 +26,24 @@ "gzip": 33273 }, "react-art.development.js (UMD_DEV)": { - "size": 342770, - "gzip": 76828 + "size": 342608, + "gzip": 76782 }, "react-art.production.min.js (UMD_PROD)": { "size": 95013, - "gzip": 28990 + "gzip": 28991 }, "react.development.js (NODE_DEV)": { - "size": 70286, - "gzip": 17600 + "size": 70266, + "gzip": 17594 }, "react.production.min.js (NODE_PROD)": { "size": 9226, - "gzip": 3626 + "gzip": 3628 }, "React-dev.js (FB_DEV)": { - "size": 72143, - "gzip": 18236 + "size": 72123, + "gzip": 18231 }, "React-prod.js (FB_PROD)": { "size": 36643, @@ -58,16 +58,16 @@ "gzip": 84675 }, "react-dom.development.js (NODE_DEV)": { - "size": 542350, - "gzip": 125199 + "size": 542188, + "gzip": 125158 }, "react-dom.production.min.js (NODE_PROD)": { "size": 116925, "gzip": 36732 }, "ReactDOMFiber-dev.js (FB_DEV)": { - "size": 797397, - "gzip": 184161 + "size": 797235, + "gzip": 184122 }, "ReactDOMFiber-prod.js (FB_PROD)": { "size": 407613, @@ -98,16 +98,16 @@ "gzip": 22993 }, "react-art.development.js (NODE_DEV)": { - "size": 265214, - "gzip": 56974 + "size": 265052, + "gzip": 56927 }, "react-art.production.min.js (NODE_PROD)": { "size": 56628, "gzip": 17152 }, "ReactARTFiber-dev.js (FB_DEV)": { - "size": 264392, - "gzip": 56780 + "size": 264230, + "gzip": 56736 }, "ReactARTFiber-prod.js (FB_PROD)": { "size": 205336, @@ -122,20 +122,20 @@ "gzip": 84001 }, "ReactTestRendererFiber-dev.js (FB_DEV)": { - "size": 262301, - "gzip": 55747 + "size": 262139, + "gzip": 55704 }, "ReactTestRendererStack-dev.js (FB_DEV)": { "size": 151521, "gzip": 34765 }, "react-noop-renderer.development.js (NODE_DEV)": { - "size": 254298, - "gzip": 53728 + "size": 254136, + "gzip": 53682 }, "react-test-renderer.development.js (NODE_DEV)": { - "size": 263132, - "gzip": 55938 + "size": 262970, + "gzip": 55891 } } } \ No newline at end of file diff --git a/src/ReactVersion.js b/src/ReactVersion.js index d6ec94ed53dee..fd32524d89f46 100644 --- a/src/ReactVersion.js +++ b/src/ReactVersion.js @@ -11,4 +11,4 @@ 'use strict'; -module.exports = '16.0.0-alpha.8'; +module.exports = '16.0.0-alpha.9'; From 446f186279f3b5197d098c2f145ca809dd090d24 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Wed, 12 Apr 2017 00:04:38 +0100 Subject: [PATCH 25/43] Update typechecking-with-proptypes.md (#9392) * Update typechecking-with-proptypes.md * Update typechecking-with-proptypes.md * Use consistent style for PropTypes import --- docs/docs/typechecking-with-proptypes.md | 62 +++++++++++++----------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/docs/docs/typechecking-with-proptypes.md b/docs/docs/typechecking-with-proptypes.md index ce5e0aedee977..85c128d3a909f 100644 --- a/docs/docs/typechecking-with-proptypes.md +++ b/docs/docs/typechecking-with-proptypes.md @@ -12,6 +12,8 @@ redirect_from: As your app grows, you can catch a lot of bugs with typechecking. For some applications, you can use JavaScript extensions like [Flow](https://flowtype.org/) or [TypeScript](https://www.typescriptlang.org/) to typecheck your whole application. But even if you don't use those, React has some built-in typechecking abilities. To run typechecking on the props for a component, you can assign the special `propTypes` property: ```javascript +import PropTypes from 'prop-types'; + class Greeting extends React.Component { render() { return ( @@ -21,68 +23,70 @@ class Greeting extends React.Component { } Greeting.propTypes = { - name: React.PropTypes.string + name: PropTypes.string }; ``` -`React.PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. In this example, we're using `React.PropTypes.string`. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. For performance reasons, `propTypes` is only checked in development mode. +`PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. In this example, we're using `PropTypes.string`. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. For performance reasons, `propTypes` is only checked in development mode. -### React.PropTypes +### PropTypes Here is an example documenting the different validators provided: ```javascript +import PropTypes from 'prop-types'; + MyComponent.propTypes = { // You can declare that a prop is a specific JS primitive. By default, these // are all optional. - optionalArray: React.PropTypes.array, - optionalBool: React.PropTypes.bool, - optionalFunc: React.PropTypes.func, - optionalNumber: React.PropTypes.number, - optionalObject: React.PropTypes.object, - optionalString: React.PropTypes.string, - optionalSymbol: React.PropTypes.symbol, + optionalArray: PropTypes.array, + optionalBool: PropTypes.bool, + optionalFunc: PropTypes.func, + optionalNumber: PropTypes.number, + optionalObject: PropTypes.object, + optionalString: PropTypes.string, + optionalSymbol: PropTypes.symbol, // Anything that can be rendered: numbers, strings, elements or an array // (or fragment) containing these types. - optionalNode: React.PropTypes.node, + optionalNode: PropTypes.node, // A React element. - optionalElement: React.PropTypes.element, + optionalElement: PropTypes.element, // You can also declare that a prop is an instance of a class. This uses // JS's instanceof operator. - optionalMessage: React.PropTypes.instanceOf(Message), + optionalMessage: PropTypes.instanceOf(Message), // You can ensure that your prop is limited to specific values by treating // it as an enum. - optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), + optionalEnum: PropTypes.oneOf(['News', 'Photos']), // An object that could be one of many types - optionalUnion: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.number, - React.PropTypes.instanceOf(Message) + optionalUnion: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.instanceOf(Message) ]), // An array of a certain type - optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + optionalArrayOf: PropTypes.arrayOf(PropTypes.number), // An object with property values of a certain type - optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + optionalObjectOf: PropTypes.objectOf(PropTypes.number), // An object taking on a particular shape - optionalObjectWithShape: React.PropTypes.shape({ - color: React.PropTypes.string, - fontSize: React.PropTypes.number + optionalObjectWithShape: PropTypes.shape({ + color: PropTypes.string, + fontSize: PropTypes.number }), // You can chain any of the above with `isRequired` to make sure a warning // is shown if the prop isn't provided. - requiredFunc: React.PropTypes.func.isRequired, + requiredFunc: PropTypes.func.isRequired, // A value of any data type - requiredAny: React.PropTypes.any.isRequired, + requiredAny: PropTypes.any.isRequired, // You can also specify a custom validator. It should return an Error // object if the validation fails. Don't `console.warn` or throw, as this @@ -101,7 +105,7 @@ MyComponent.propTypes = { // will be called for each key in the array or object. The first two // arguments of the validator are the array or object itself, and the // current item's key. - customArrayProp: React.PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) { + customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) { if (!/matchme/.test(propValue[key])) { return new Error( 'Invalid prop `' + propFullName + '` supplied to' + @@ -114,9 +118,11 @@ MyComponent.propTypes = { ### Requiring Single Child -With `React.PropTypes.element` you can specify that only a single child can be passed to a component as children. +With `PropTypes.element` you can specify that only a single child can be passed to a component as children. ```javascript +import PropTypes from 'prop-types'; + class MyComponent extends React.Component { render() { // This must be exactly one element or it will warn. @@ -130,7 +136,7 @@ class MyComponent extends React.Component { } MyComponent.propTypes = { - children: React.PropTypes.element.isRequired + children: PropTypes.element.isRequired }; ``` From 5cd44d21e9eb1e5014b9ae2109268600ce1c360f Mon Sep 17 00:00:00 2001 From: hanumanthan Date: Thu, 13 Apr 2017 05:26:22 +0530 Subject: [PATCH 26/43] Refractor docs to indicate that state set to props in constructor will not recieve the updated props (#9404) --- docs/docs/reference-react-component.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/reference-react-component.md b/docs/docs/reference-react-component.md index d8c2be7302fec..03c3bcba2d0de 100644 --- a/docs/docs/reference-react-component.md +++ b/docs/docs/reference-react-component.md @@ -113,7 +113,7 @@ The constructor for a React component is called before it is mounted. When imple The constructor is the right place to initialize state. If you don't initialize state and you don't bind methods, you don't need to implement a constructor for your React component. -It's okay to initialize state based on props if you know what you're doing. Here's an example of a valid `React.Component` subclass constructor: +It's okay to initialize state based on props. This effectively "forks" the props and sets the state with the initial props. Here's an example of a valid `React.Component` subclass constructor: ```js constructor(props) { @@ -124,7 +124,7 @@ constructor(props) { } ``` -Beware of this pattern, as it effectively "forks" the props and can lead to bugs. Instead of syncing props to state, you often want to [lift the state up](/react/docs/lifting-state-up.html). +Beware of this pattern, as state won't be up-to-date with any props update. Instead of syncing props to state, you often want to [lift the state up](/react/docs/lifting-state-up.html). If you "fork" props by using them for state, you might also want to implement [`componentWillReceiveProps(nextProps)`](#componentwillreceiveprops) to keep the state up-to-date with them. But lifting state up is often easier and less bug-prone. From 22655d5759235a783546405763db2c9f9bace29d Mon Sep 17 00:00:00 2001 From: Gabriel Lett Viviani Date: Thu, 13 Apr 2017 11:15:34 -0300 Subject: [PATCH 27/43] Fix the proptypes deprecation warning url on the "Don't Call PropTypes Warning" doc page (#9419) * Use the same prop-types link on the warning docs page as the main proptypes doc page * Link to repo instead --- docs/warnings/dont-call-proptypes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/warnings/dont-call-proptypes.md b/docs/warnings/dont-call-proptypes.md index bc468689af3ba..05da5c04c73ec 100644 --- a/docs/warnings/dont-call-proptypes.md +++ b/docs/warnings/dont-call-proptypes.md @@ -5,7 +5,7 @@ permalink: warnings/dont-call-proptypes.html --- > Note: -> `React.PropTypes` is deprecated as of React v15.5. Please use [the `prop-types` library instead](https://github.com/aackerman/PropTypes). +> `React.PropTypes` is deprecated as of React v15.5. Please use [the `prop-types` library instead](https://github.com/reactjs/prop-types). In a future major release of React, the code that implements PropType validation functions will be stripped in production. Once this happens, any code that calls these functions manually (that isn't stripped in production) will throw an error. From 4e0c57315afc2769fe13bbbb4235b0aa47343ca7 Mon Sep 17 00:00:00 2001 From: Jack Date: Fri, 14 Apr 2017 03:11:23 +1000 Subject: [PATCH 28/43] Update proptypes doc (#9391) * Update proptypes doc * Removed note --- docs/contributing/codebase-overview.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/contributing/codebase-overview.md b/docs/contributing/codebase-overview.md index 637c4893241ec..b9be535b416bc 100644 --- a/docs/contributing/codebase-overview.md +++ b/docs/contributing/codebase-overview.md @@ -301,10 +301,8 @@ While the code is separated in the source tree, the exact package boundaries are The "core" of React includes all the [top-level `React` APIs](/react/docs/top-level-api.html#react), for example: * `React.createElement()` -* `React.createClass()` * `React.Component` * `React.Children` -* `React.PropTypes` **React core only includes the APIs necessary to define components.** It does not include the [reconciliation](/react/docs/reconciliation.html) algorithm or any platform-specific code. It is used both by React DOM and React Native components. From 30d6c598c6fa06e087ffa2ff32356a66917c68de Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Thu, 13 Apr 2017 08:13:55 -1000 Subject: [PATCH 29/43] Docs: Clarification of setState() behavior (#9329) * Clarification of setState() behavior `setState()` is a frequent source of confusion for people new to React, and I believe part of that is due to minimization of the impact of the asynchronous behavior of `setState()` in the documentation. This revision is an attempt to clarify that behavior. For motivation and justification, see [setState Gate](https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82). * Update reference-react-component.md * Signature fix * Update to address @acdlite concerns * Add more details --- docs/docs/reference-react-component.md | 55 ++++++++++++++++++++------ 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/docs/docs/reference-react-component.md b/docs/docs/reference-react-component.md index 03c3bcba2d0de..67efaae6a74f1 100644 --- a/docs/docs/reference-react-component.md +++ b/docs/docs/reference-react-component.md @@ -229,34 +229,67 @@ componentWillUnmount() ### `setState()` ```javascript -setState(nextState, callback) +setState(updater, [callback]) ``` -Performs a shallow merge of nextState into current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. +`setState()` enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses. -The first argument can be an object (containing zero or more keys to update) or a function (of state and props) that returns an object containing keys to update. +Think of `setState()` as a *request* rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately. -Here is the simple object usage: +`setState()` does not always immediately update the component. It may batch or defer the update until later. This makes reading `this.state` right after calling `setState()` a potential pitfall. Instead, use `componentDidUpdate` or a `setState` callback (`setState(updater, callback)`), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the `updater` argument below. + +`setState()` will always lead to a re-render unless `shouldComponentUpdate()` returns `false`. If mutable objects are being used and conditional rendering logic cannot be implemented in `shouldComponentUpdate()`, calling `setState()` only when the new state differs from the previous state will avoid unnecessary re-renders. + +The first argument is an `updater` function with the signature: ```javascript -this.setState({mykey: 'my new value'}); +(prevState, props) => nextState ``` -It's also possible to pass a function with the signature `function(state, props) => newState`. This enqueues an atomic update that consults the previous value of state and props before setting any values. For instance, suppose we wanted to increment a value in state by `props.step`: +`prevState` is a reference to the previous state. It should not be directly mutated. Instead, changes should be represented by building a new state object based on the input from `prevState` and `props`. For instance, suppose we wanted to increment a value in state by `props.step`: ```javascript this.setState((prevState, props) => { - return {myInteger: prevState.myInteger + props.step}; + return {counter: prevState.counter + props.step}; }); ``` -The second parameter is an optional callback function that will be executed once `setState` is completed and the component is re-rendered. Generally we recommend using `componentDidUpdate()` for such logic instead. +Both `prevState` and `props` received by the updater function are guaranteed to be up-to-date. -`setState()` does not immediately mutate `this.state` but creates a pending state transition. Accessing `this.state` after calling this method can potentially return the existing value. +The second parameter to `setState()` is an optional callback function that will be executed once `setState` is completed and the component is re-rendered. Generally we recommend using `componentDidUpdate()` for such logic instead. -There is no guarantee of synchronous operation of calls to `setState` and calls may be batched for performance gains. +You may optionally pass an object as the first argument to `setState()` instead of a function: -`setState()` will always lead to a re-render unless `shouldComponentUpdate()` returns `false`. If mutable objects are being used and conditional rendering logic cannot be implemented in `shouldComponentUpdate()`, calling `setState()` only when the new state differs from the previous state will avoid unnecessary re-renders. +```javascript +setState(stateChange, [callback]) +``` + +This performs a shallow merge of `stateChange` into the new state, e.g., to adjust a shopping cart item quantity: + +```javascript +this.setState({quantity: 2}) +``` + +This form of `setState()` is also asynchronous, and multiple calls during the same cycle may be batched together. For example, if you attempt to increment an item quantity more than once in the same cycle, that will result in the equivalent of: + +```javaScript +Object.assign( + previousState, + {quantity: state.quantity + 1}, + {quantity: state.quantity + 1}, + ... +) +``` + +Subsequent calls will override values from previous calls in the same cycle, so the quantity will only be incremented once. If the next state depends on the previous state, we recommend using the updater function form, instead: + +```js +this.setState((prevState) => { + return {counter: prevState.quantity + 1}; +}); +``` + +For more detail, see the [State and Lifecycle guide](/react/docs/state-and-lifecycle.html). * * * From 855b8d3526a55e690108e8ede9091c14b6f62466 Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Thu, 13 Apr 2017 21:54:12 +0200 Subject: [PATCH 30/43] Add tabs to installation page (#9275, #9277) (#9401) * Add tabs to installation page (#9275, #9277) This adds tabs for create-react-app and existing apps to the installation section of the docs. The tab implementation is a simplified version of React Native's installation page. Fixes #9275. * Use classList instead of className * Use same implementation as in RN --- docs/docs/installation.md | 94 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/docs/docs/installation.md b/docs/docs/installation.md index d4ee06ae54422..8f583117ef408 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -11,27 +11,86 @@ redirect_from: - "docs/environments.html" next: hello-world.html --- + React is flexible and can be used in a variety of projects. You can create new apps with it, but you can also gradually introduce it into an existing codebase without doing a rewrite. +
    + + + Which of these options best describes what you want to do? +
    +
    + Try React + Create a New App + Add React to an Existing App +
    + + + ## Trying Out React If you're just interested in playing around with React, you can use CodePen. Try starting from [this Hello World example code](http://codepen.io/gaearon/pen/rrpgNB?editors=0010). You don't need to install anything; you can just modify the code and see if it works. If you prefer to use your own text editor, you can also
    download this HTML file, edit it, and open it from the local filesystem in your browser. It does a slow runtime code transformation, so don't use it in production. -## Creating a Single Page Application +If you want to use it for a full application, there are two popular ways to get started with React: using Create React App, or adding it to an existing application. + + + +## Creating a New Application [Create React App](http://github.com/facebookincubator/create-react-app) is the best way to start building a new React single page application. It sets up your development environment so that you can use the latest JavaScript features, provides a nice developer experience, and optimizes your app for production. ```bash npm install -g create-react-app -create-react-app hello-world -cd hello-world +create-react-app my-app + +cd my-app npm start ``` -Create React App doesn't handle backend logic or databases; it just creates a frontend build pipeline, so you can use it with any backend you want. It uses [webpack](https://webpack.js.org/), [Babel](http://babeljs.io/) and [ESLint](http://eslint.org/) under the hood, but configures them for you. +Create React App doesn't handle backend logic or databases; it just creates a frontend build pipeline, so you can use it with any backend you want. It uses build tools like Babel and webpack under the hood, but works with zero configuration. + + ## Adding React to an Existing Application @@ -134,3 +193,30 @@ The versions above are only meant for development, and are not suitable for prod To load a specific version of `react` and `react-dom`, replace `15` with the version number. If you use Bower, React is available via the `react` package. + + \ No newline at end of file From 4c8c5debac5074427d5e6ce19896d4062e078a83 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 13 Apr 2017 21:51:19 +0100 Subject: [PATCH 31/43] Switch Installation to a tab when hash is present (#9422) --- docs/docs/installation.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/docs/installation.md b/docs/docs/installation.md index 8f583117ef408..3072d7768e7eb 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -195,6 +195,10 @@ To load a specific version of `react` and `react-dom`, replace `15` with the ver If you use Bower, React is available via the `react` package. \ No newline at end of file From a95e1d8ffcbfaaa2eda98d1bf914d1b750c402c8 Mon Sep 17 00:00:00 2001 From: Abhay Nikam Date: Fri, 14 Apr 2017 03:45:13 +0530 Subject: [PATCH 32/43] Updated recommended links for installation in readme (#9425) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df717360fee9a..e22b705c1eb9c 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ React is flexible and can be used in a variety of projects. You can create new a The recommended way to install React depends on your project. Here you can find short guides for the most common scenarios: * [Trying Out React](https://facebook.github.io/react/docs/installation.html#trying-out-react) -* [Creating a Single Page Application](https://facebook.github.io/react/docs/installation.html#creating-a-single-page-application) +* [Creating a New Application](https://facebook.github.io/react/docs/installation.html#creating-a-new-application) * [Adding React to an Existing Application](https://facebook.github.io/react/docs/installation.html#adding-react-to-an-existing-application) ## Contributing From db989c0f63e1b4700ad33a64c776d1b34bd206f7 Mon Sep 17 00:00:00 2001 From: Vikash Agrawal Date: Fri, 14 Apr 2017 21:26:38 +0530 Subject: [PATCH 33/43] Updated link for good first bug's in README.md (#9273) * Updated link for good first bug's in README.md * Changed text for beginner friendly bugs * update beginner friendly bugs section title --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e22b705c1eb9c..2ae261c6994a9 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ Facebook has adopted a Code of Conduct that we expect project participants to ad Read our [contributing guide](https://facebook.github.io/react/contributing/how-to-contribute.html) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React. -### Good First Bug +### Beginner Friendly Bugs -To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first bugs](https://github.com/facebook/react/labels/good%20first%20bug) that contain bugs which are fairly easy to fix. This is a great place to get started. +To help you get your feet wet and get you familiar with our contribution process, we have a list of [beginner friendly bugs](https://github.com/facebook/react/labels/Difficulty%3A%20beginner) that contain bugs which are fairly easy to fix. This is a great place to get started. ### License From 36c935ca8f9df7e19b5051997f4eb381402113ac Mon Sep 17 00:00:00 2001 From: Abhay Nikam Date: Fri, 14 Apr 2017 21:32:07 +0530 Subject: [PATCH 34/43] Updated the Good First Bug section in readme (#9429) * Updated the Good First Bug section in readme * Inconsistent use of quotes. Prefered single quotes instead of double quotes * Updated Good first bug link in how_to_contribute doc. * Undo JSX attribute quote change * don't capitalize "beginner friendly issue" --- docs/contributing/how-to-contribute.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md index 5b2c6c5031171..b45eb1798b949 100644 --- a/docs/contributing/how-to-contribute.md +++ b/docs/contributing/how-to-contribute.md @@ -64,7 +64,7 @@ Working on your first Pull Request? You can learn how from this free video serie **[How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)** -To help you get your feet wet and get you familiar with our contribution process, we have a list of **[good first bugs](https://github.com/facebook/react/labels/good%20first%20bug)** that contain bugs which are fairly easy to fix. This is a great place to get started. +To help you get your feet wet and get you familiar with our contribution process, we have a list of **[beginner friendly issues](https://github.com/facebook/react/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+beginner%22)** that contain bugs which are fairly easy to fix. This is a great place to get started. If you decide to fix an issue, please be sure to check the comment thread in case somebody is already working on a fix. If nobody is working on it at the moment, please leave a comment stating that you intend to work on it so other people don't accidentally duplicate your effort. @@ -101,7 +101,7 @@ In order to accept your pull request, we need you to submit a CLA. You only need ### Development Workflow -After cloning React, run `npm install` to fetch its dependencies. +After cloning React, run `npm install` to fetch its dependencies. Then, you can run several commands: * `npm run lint` checks the code style. From f54fdd544198ba7f76aafb9e5f4e4a8be137ac4c Mon Sep 17 00:00:00 2001 From: Arshabh Kumar Agarwal Date: Fri, 14 Apr 2017 22:00:38 +0530 Subject: [PATCH 35/43] Add warning if rendering and HTMLUnknownElement (#9163) * Add warning if rendering and HTMLUnknownElement * Records fiber tests * Fixes linting and server render tests * Incorporates review comments * Uses ownerDocument instead of document * uses el instead of creating a new element * Removes warning check of voidElementTags * Add missing space to unknown element warning * Only call isCustomComponent once * Spy on console in menuitem test Since menuitem is treated as an unknown element in jsdom it triggers the unknown element warning. * Add unknown element warning to Fiber * Replace instanceof with toString check It is more resilient. * Record tests --- scripts/fiber/tests-passing.txt | 1 + .../dom/fiber/ReactDOMFiberComponent.js | 19 ++++++++- .../__tests__/ReactDOMComponent-test.js | 28 +++++++++++++ .../dom/stack/client/ReactDOMComponent.js | 40 +++++++++++++------ 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 485f3921f4f45..0cf8d024093b5 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -874,6 +874,7 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js * should work error event on element * should not duplicate uppercased selfclosing tags * should warn on upper case HTML tags, not SVG nor custom tags +* should warn if the tag is unrecognized * should warn against children for void elements * should warn against dangerouslySetInnerHTML for void elements * should include owner rather than parent in warnings diff --git a/src/renderers/dom/fiber/ReactDOMFiberComponent.js b/src/renderers/dom/fiber/ReactDOMFiberComponent.js index bea2bf0ca5a0c..7aea3c569735a 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberComponent.js +++ b/src/renderers/dom/fiber/ReactDOMFiberComponent.js @@ -418,10 +418,13 @@ var ReactDOMFiberComponent = { if (namespaceURI === HTML_NAMESPACE) { namespaceURI = getIntrinsicNamespace(type); } + if (__DEV__) { + var isCustomComponentTag = isCustomComponent(type, props); + } if (namespaceURI === HTML_NAMESPACE) { if (__DEV__) { warning( - type === type.toLowerCase() || isCustomComponent(type, props), + isCustomComponentTag || type === type.toLowerCase(), '<%s /> is using uppercase HTML. Always use lowercase HTML tags ' + 'in React.', type, @@ -448,6 +451,20 @@ var ReactDOMFiberComponent = { domElement = ownerDocument.createElementNS(namespaceURI, type); } + if (__DEV__) { + if (namespaceURI === HTML_NAMESPACE) { + warning( + isCustomComponentTag || + Object.prototype.toString.call(domElement) !== + '[object HTMLUnknownElement]', + 'The tag <%s> is unrecognized in this browser. ' + + 'If you meant to render a React component, start its name with ' + + 'an uppercase letter.', + type, + ); + } + } + return domElement; }, diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index 34f03e5be0dac..ca2ec1cf0079b 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -809,6 +809,32 @@ describe('ReactDOMComponent', () => { ); }); + it('should warn if the tag is unrecognized', () => { + if (ReactDOMFeatureFlags.useCreateElement) { + spyOn(console, 'error'); + + let realToString; + try { + realToString = Object.prototype.toString; + Object.prototype.toString = function() { + // Emulate browser behavior which is missing in jsdom + if (this instanceof window.HTMLUnknownElement) { + return '[object HTMLUnknownElement]'; + } + return realToString.apply(this, arguments); + }; + ReactTestUtils.renderIntoDocument(); + } finally { + Object.prototype.toString = realToString; + } + + expectDev(console.error.calls.count()).toBe(1); + expectDev(console.error.calls.argsFor(0)[0]).toContain( + 'The tag is unrecognized in this browser', + ); + } + }); + it('should warn against children for void elements', () => { var container = document.createElement('div'); @@ -917,6 +943,8 @@ describe('ReactDOMComponent', () => { }); it('should treat menuitem as a void element but still create the closing tag', () => { + // menuitem is not implemented in jsdom, so this triggers the unknown warning error + spyOn(console, 'error'); var container = document.createElement('div'); var returnedValue = ReactDOMServer.renderToString( diff --git a/src/renderers/dom/stack/client/ReactDOMComponent.js b/src/renderers/dom/stack/client/ReactDOMComponent.js index ac717f96c7366..35e54f7b4efe8 100644 --- a/src/renderers/dom/stack/client/ReactDOMComponent.js +++ b/src/renderers/dom/stack/client/ReactDOMComponent.js @@ -485,6 +485,9 @@ ReactDOMComponent.Mixin = { assertValidProps(this, props); + if (__DEV__) { + var isCustomComponentTag = isCustomComponent(this._tag, props); + } // We create tags in the namespace of their parent container, except HTML // tags get no namespace. var namespaceURI; @@ -505,8 +508,7 @@ ReactDOMComponent.Mixin = { if (namespaceURI === DOMNamespaces.html) { if (__DEV__) { warning( - isCustomComponent(this._tag, props) || - this._tag === this._currentElement.type, + isCustomComponentTag || this._tag === this._currentElement.type, '<%s /> is using uppercase HTML. Always use lowercase HTML tags ' + 'in React.', this._currentElement.type, @@ -562,17 +564,29 @@ ReactDOMComponent.Mixin = { } else { el = ownerDocument.createElementNS(namespaceURI, type); } - var isCustomComponentTag = isCustomComponent(this._tag, props); - if (__DEV__ && isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) { - var owner = this._currentElement._owner; - var name = (owner && owner.getName()) || 'A component'; - warning( - false, - '%s is using shady DOM. Using shady DOM with React can ' + - 'cause things to break subtly.', - name, - ); - didWarnShadyDOM = true; + if (__DEV__) { + if (isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) { + var owner = this._currentElement._owner; + var name = (owner && owner.getName()) || 'A component'; + warning( + false, + '%s is using shady DOM. Using shady DOM with React can ' + + 'cause things to break subtly.', + name, + ); + didWarnShadyDOM = true; + } + if (this._namespaceURI === DOMNamespaces.html) { + warning( + isCustomComponentTag || + Object.prototype.toString.call(el) !== + '[object HTMLUnknownElement]', + 'The tag <%s> is unrecognized in this browser. ' + + 'If you meant to render a React component, start its name with ' + + 'an uppercase letter.', + this._tag, + ); + } } ReactDOMComponentTree.precacheNode(this, el); this._flags |= Flags.hasCachedChildNodes; From 1447d9f1ae699b46c31d6c8b7f0e57212d6c7f1e Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Fri, 14 Apr 2017 16:57:47 -0700 Subject: [PATCH 36/43] Add component stack to uncontrolled-to-controlled warning (#9416) https://twitter.com/JulianVModesto/status/836089555304448000 https://twitter.com/abevoelker/status/836040051993763842 --- .../dom/fiber/wrappers/ReactDOMFiberInput.js | 16 ++- .../wrappers/__tests__/ReactDOMInput-test.js | 116 ++++++++++-------- .../stack/client/wrappers/ReactDOMInput.js | 19 +-- 3 files changed, 90 insertions(+), 61 deletions(-) diff --git a/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js b/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js index f0bbc0adcaef3..01ee87f95dfb3 100644 --- a/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js +++ b/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js @@ -25,6 +25,10 @@ var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber'); +if (__DEV__) { + var {getCurrentFiberStackAddendum} = require('ReactDebugCurrentFiber'); +} + var invariant = require('fbjs/lib/invariant'); var warning = require('fbjs/lib/warning'); @@ -154,12 +158,12 @@ var ReactDOMInput = { ) { warning( false, - '%s is changing an uncontrolled input of type %s to be controlled. ' + + 'A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', - getCurrentFiberOwnerName() || 'A component', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, + getCurrentFiberStackAddendum(), ); didWarnUncontrolledToControlled = true; } @@ -170,12 +174,12 @@ var ReactDOMInput = { ) { warning( false, - '%s is changing a controlled input of type %s to be uncontrolled. ' + + 'A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', - getCurrentFiberOwnerName() || 'A component', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, + getCurrentFiberStackAddendum(), ); didWarnControlledToUncontrolled = true; } diff --git a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js index 102acc241800c..08e53783f8c6f 100644 --- a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js @@ -21,6 +21,10 @@ describe('ReactDOMInput', () => { var ReactTestUtils; var inputValueTracking; + function normalizeCodeLocInfo(str) { + return str && str.replace(/\(at .+?:\d+\)/g, '(at **)'); + } + function setUntrackedValue(elem, value) { var tracker = inputValueTracking._getTrackerFromNode(elem); var current = tracker.getValue(); @@ -738,11 +742,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type text to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type text to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -754,11 +759,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBeGreaterThan(0); - expectDev(console.error.calls.argsFor(1)[0]).toContain( - 'A component is changing a controlled input of type text to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( + 'Warning: A component is changing a controlled input of type text to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -773,11 +779,12 @@ describe('ReactDOMInput', () => { container, ); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type text to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type text to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -787,11 +794,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing an uncontrolled input of type text to be controlled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing an uncontrolled input of type text to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -801,11 +809,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBeGreaterThan(0); - expectDev(console.error.calls.argsFor(1)[0]).toContain( - 'A component is changing an uncontrolled input of type text to be controlled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( + 'Warning: A component is changing an uncontrolled input of type text to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -817,11 +826,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type checkbox to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type checkbox to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -833,11 +843,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type checkbox to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type checkbox to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -849,11 +860,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type checkbox to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type checkbox to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -863,11 +875,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing an uncontrolled input of type checkbox to be controlled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing an uncontrolled input of type checkbox to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -877,11 +890,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing an uncontrolled input of type checkbox to be controlled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing an uncontrolled input of type checkbox to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -891,11 +905,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type radio to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type radio to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -905,11 +920,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type radio to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type radio to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -919,11 +935,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type radio to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type radio to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -933,11 +950,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing an uncontrolled input of type radio to be controlled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing an uncontrolled input of type radio to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -947,11 +965,12 @@ describe('ReactDOMInput', () => { ReactDOM.render(stub, container); ReactDOM.render(, container); expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing an uncontrolled input of type radio to be controlled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing an uncontrolled input of type radio to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); @@ -1002,11 +1021,12 @@ describe('ReactDOMInput', () => { container, ); ReactDOM.render(, container); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'A component is changing a controlled input of type radio to be uncontrolled. ' + + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: A component is changing a controlled input of type radio to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components\n' + + ' in input (at **)', ); }); diff --git a/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js b/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js index 2f30e43a26f5e..8e7f6de01a825 100644 --- a/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js +++ b/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js @@ -18,6 +18,12 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree'); var invariant = require('fbjs/lib/invariant'); var warning = require('fbjs/lib/warning'); +if (__DEV__) { + var { + getStackAddendumByID, + } = require('ReactGlobalSharedState').ReactComponentTreeHook; +} + var didWarnValueDefaultValue = false; var didWarnCheckedDefaultChecked = false; var didWarnControlledToUncontrolled = false; @@ -137,7 +143,6 @@ var ReactDOMInput = { if (__DEV__) { var controlled = isControlled(props); - var owner = inst._currentElement._owner; if ( !inst._wrapperState.controlled && @@ -146,12 +151,12 @@ var ReactDOMInput = { ) { warning( false, - '%s is changing an uncontrolled input of type %s to be controlled. ' + + 'A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', - (owner && owner.getName()) || 'A component', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, + getStackAddendumByID(inst._debugID), ); didWarnUncontrolledToControlled = true; } @@ -162,12 +167,12 @@ var ReactDOMInput = { ) { warning( false, - '%s is changing a controlled input of type %s to be uncontrolled. ' + + 'A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + - 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', - (owner && owner.getName()) || 'A component', + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, + getStackAddendumByID(inst._debugID), ); didWarnControlledToUncontrolled = true; } From 7bf686b76f20eca07f0abef1bf6a0f0380b0c3f2 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Fri, 14 Apr 2017 19:50:43 -0700 Subject: [PATCH 37/43] Add component stack to ReactControlledValuePropTypes (#9435) --- .../dom/fiber/wrappers/ReactDOMFiberInput.js | 2 +- .../dom/fiber/wrappers/ReactDOMFiberSelect.js | 6 +++++- .../dom/fiber/wrappers/ReactDOMFiberTextarea.js | 7 +++++-- .../shared/utils/ReactControlledValuePropTypes.js | 11 ++--------- .../wrappers/__tests__/ReactDOMInput-test.js | 7 +++++++ .../dom/stack/client/wrappers/ReactDOMInput.js | 7 ++----- .../dom/stack/client/wrappers/ReactDOMSelect.js | 13 ++++++++----- .../dom/stack/client/wrappers/ReactDOMTextarea.js | 14 ++++++++------ 8 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js b/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js index 01ee87f95dfb3..ebc9812077ea2 100644 --- a/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js +++ b/src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js @@ -94,7 +94,7 @@ var ReactDOMInput = { ReactControlledValuePropTypes.checkPropTypes( 'input', props, - getCurrentFiberOwnerName(), + getCurrentFiberStackAddendum, ); if ( diff --git a/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js b/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js index 2ceb3114b1bf7..4659ec7f01350 100644 --- a/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js +++ b/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js @@ -23,6 +23,10 @@ var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes'); var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber'); var warning = require('fbjs/lib/warning'); +if (__DEV__) { + var {getCurrentFiberStackAddendum} = require('ReactDebugCurrentFiber'); +} + var didWarnValueDefaultValue = false; function getDeclarationErrorAddendum() { @@ -42,7 +46,7 @@ function checkSelectPropTypes(props) { ReactControlledValuePropTypes.checkPropTypes( 'select', props, - getCurrentFiberOwnerName(), + getCurrentFiberStackAddendum, ); for (var i = 0; i < valuePropNames.length; i++) { diff --git a/src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js b/src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js index 43c91a362372a..2f99352a0aaa1 100644 --- a/src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js +++ b/src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js @@ -19,11 +19,14 @@ type TextAreaWithWrapperState = HTMLTextAreaElement & { }; var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes'); -var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber'); var invariant = require('fbjs/lib/invariant'); var warning = require('fbjs/lib/warning'); +if (__DEV__) { + var {getCurrentFiberStackAddendum} = require('ReactDebugCurrentFiber'); +} + var didWarnValDefaultVal = false; /** @@ -69,7 +72,7 @@ var ReactDOMTextarea = { ReactControlledValuePropTypes.checkPropTypes( 'textarea', props, - getCurrentFiberOwnerName(), + getCurrentFiberStackAddendum, ); if ( props.value !== undefined && diff --git a/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js b/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js index 0f8b44bc81e4d..48c37b67a3039 100644 --- a/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js +++ b/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js @@ -61,19 +61,13 @@ var propTypes = { }; var loggedTypeFailures = {}; -function getDeclarationErrorAddendum(ownerName) { - if (ownerName) { - return '\n\nCheck the render method of `' + ownerName + '`.'; - } - return ''; -} /** * Provide a linked `value` attribute for controlled forms. You should not use * this outside of the ReactDOM controlled form components. */ var ReactControlledValuePropTypes = { - checkPropTypes: function(tagName, props, ownerName) { + checkPropTypes: function(tagName, props, getStack) { for (var propName in propTypes) { if (propTypes.hasOwnProperty(propName)) { var error = propTypes[propName]( @@ -90,8 +84,7 @@ var ReactControlledValuePropTypes = { // same error. loggedTypeFailures[error.message] = true; - var addendum = getDeclarationErrorAddendum(ownerName); - warning(false, 'Failed form propType: %s%s', error.message, addendum); + warning(false, 'Failed form propType: %s%s', error.message, getStack()); } } }, diff --git a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js index 08e53783f8c6f..ac76902e0cf15 100644 --- a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js @@ -642,6 +642,13 @@ describe('ReactDOMInput', () => { , ); expectDev(console.error.calls.count()).toBe(1); + expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( + 'Warning: Failed form propType: You provided a `value` prop to a form ' + + 'field without an `onChange` handler. This will render a read-only ' + + 'field. If the field should be mutable use `defaultValue`. ' + + 'Otherwise, set either `onChange` or `readOnly`.\n' + + ' in input (at **)', + ); }); it('should have a this value of undefined if bind is not used', () => { diff --git a/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js b/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js index 8e7f6de01a825..cf0bb9cadc0f9 100644 --- a/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js +++ b/src/renderers/dom/stack/client/wrappers/ReactDOMInput.js @@ -83,11 +83,8 @@ var ReactDOMInput = { mountWrapper: function(inst, props) { if (__DEV__) { var owner = inst._currentElement._owner; - ReactControlledValuePropTypes.checkPropTypes( - 'input', - props, - owner ? owner.getName() : null, - ); + ReactControlledValuePropTypes.checkPropTypes('input', props, () => + getStackAddendumByID(inst._debugID)); if ( props.checked !== undefined && diff --git a/src/renderers/dom/stack/client/wrappers/ReactDOMSelect.js b/src/renderers/dom/stack/client/wrappers/ReactDOMSelect.js index efc98b4134539..1d8bbb9721429 100644 --- a/src/renderers/dom/stack/client/wrappers/ReactDOMSelect.js +++ b/src/renderers/dom/stack/client/wrappers/ReactDOMSelect.js @@ -16,6 +16,12 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree'); var warning = require('fbjs/lib/warning'); +if (__DEV__) { + var { + getStackAddendumByID, + } = require('ReactGlobalSharedState').ReactComponentTreeHook; +} + var didWarnValueDefaultValue = false; function getDeclarationErrorAddendum(owner) { @@ -36,11 +42,8 @@ var valuePropNames = ['value', 'defaultValue']; */ function checkSelectPropTypes(inst, props) { var owner = inst._currentElement._owner; - ReactControlledValuePropTypes.checkPropTypes( - 'select', - props, - owner ? owner.getName() : null, - ); + ReactControlledValuePropTypes.checkPropTypes('select', props, () => + getStackAddendumByID(inst._debugID)); for (var i = 0; i < valuePropNames.length; i++) { var propName = valuePropNames[i]; diff --git a/src/renderers/dom/stack/client/wrappers/ReactDOMTextarea.js b/src/renderers/dom/stack/client/wrappers/ReactDOMTextarea.js index 4ddf9e51a87b2..4f20530b4eb57 100644 --- a/src/renderers/dom/stack/client/wrappers/ReactDOMTextarea.js +++ b/src/renderers/dom/stack/client/wrappers/ReactDOMTextarea.js @@ -17,6 +17,12 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree'); var invariant = require('fbjs/lib/invariant'); var warning = require('fbjs/lib/warning'); +if (__DEV__) { + var { + getStackAddendumByID, + } = require('ReactGlobalSharedState').ReactComponentTreeHook; +} + var didWarnValDefaultVal = false; /** @@ -57,12 +63,8 @@ var ReactDOMTextarea = { mountWrapper: function(inst, props) { if (__DEV__) { - var owner = inst._currentElement._owner; - ReactControlledValuePropTypes.checkPropTypes( - 'textarea', - props, - owner ? owner.getName() : null, - ); + ReactControlledValuePropTypes.checkPropTypes('textarea', props, () => + getStackAddendumByID(inst._debugID)); if ( props.value !== undefined && props.defaultValue !== undefined && From ac9d6986364fd94cd8dd0dde219b2a32a17d60e2 Mon Sep 17 00:00:00 2001 From: Sung Won Cho Date: Sun, 16 Apr 2017 03:37:12 +1000 Subject: [PATCH 38/43] Make nodeType into constant for readability and reuse (#9113) * Make nodeType into constant for readability and reuse * Fix eslint line length warning * Delete unused nodeType values * Destructure HTMLNodeType constant * Make nodeType into constant for readability and reuse * Fix eslint line length warning * Delete unused nodeType values * Destructure HTMLNodeType constant * Fix test * Format using prettier --- .../no-primitive-constructors-test.js | 6 +++-- src/renderers/dom/fiber/ReactDOMFiber.js | 19 +++++++------ .../dom/fiber/ReactDOMFiberComponent.js | 7 +++-- src/renderers/dom/shared/HTMLNodeType.js | 26 ++++++++++++++++++ .../dom/shared/ReactDOMComponentTree.js | 8 +++--- .../dom/shared/ReactInputSelection.js | 3 ++- .../shared/eventPlugins/SelectEventPlugin.js | 3 ++- src/renderers/dom/shared/findDOMNode.js | 3 ++- src/renderers/dom/shared/setTextContent.js | 7 +++-- .../dom/shared/utils/getEventTarget.js | 4 ++- .../shared/utils/getNodeForCharacterOffset.js | 4 ++- src/renderers/dom/stack/client/DOMLazyTree.js | 9 +++---- .../dom/stack/client/ReactDOMComponent.js | 6 ++--- .../dom/stack/client/ReactDOMContainerInfo.js | 5 ++-- .../dom/stack/client/ReactDOMTextComponent.js | 5 +++- src/renderers/dom/stack/client/ReactMount.js | 27 ++++++++++--------- 16 files changed, 89 insertions(+), 53 deletions(-) create mode 100644 src/renderers/dom/shared/HTMLNodeType.js diff --git a/eslint-rules/__tests__/no-primitive-constructors-test.js b/eslint-rules/__tests__/no-primitive-constructors-test.js index 5d1a19ef18ce4..d756beabc34a2 100644 --- a/eslint-rules/__tests__/no-primitive-constructors-test.js +++ b/eslint-rules/__tests__/no-primitive-constructors-test.js @@ -34,8 +34,10 @@ ruleTester.run('eslint-rules/no-primitive-constructors', rule, { code: 'String(obj)', errors: [ { - message: 'Do not use the String constructor. To cast a value to a string, ' + - 'concat it with the empty string (unless it\'s a symbol, which has different semantics): \'\' + value', + message: + 'Do not use the String constructor. ' + + 'To cast a value to a string, concat it with the empty string ' + + '(unless it\'s a symbol, which has different semantics): \'\' + value', }, ], }, diff --git a/src/renderers/dom/fiber/ReactDOMFiber.js b/src/renderers/dom/fiber/ReactDOMFiber.js index 80598dfb69079..bb327bb36b441 100644 --- a/src/renderers/dom/fiber/ReactDOMFiber.js +++ b/src/renderers/dom/fiber/ReactDOMFiber.js @@ -30,6 +30,11 @@ var ReactInstanceMap = require('ReactInstanceMap'); var ReactPortal = require('ReactPortal'); var {isValidElement} = require('react'); var {injectInternals} = require('ReactFiberDevToolsHook'); +var { + ELEMENT_NODE, + DOCUMENT_NODE, + DOCUMENT_FRAGMENT_NODE, +} = require('HTMLNodeType'); var findDOMNode = require('findDOMNode'); var invariant = require('fbjs/lib/invariant'); @@ -52,8 +57,6 @@ if (__DEV__) { var {updatedAncestorInfo} = validateDOMNesting; } -const DOCUMENT_NODE = 9; - ReactDOMInjection.inject(); ReactControlledComponent.injection.injectFiberControlledHostComponent( ReactDOMFiberComponent, @@ -83,10 +86,6 @@ type HostContext = HostContextDev | HostContextProd; let eventsEnabled: ?boolean = null; let selectionInformation: ?mixed = null; -var ELEMENT_NODE_TYPE = 1; -var DOC_NODE_TYPE = 9; -var DOCUMENT_FRAGMENT_NODE_TYPE = 11; - /** * True if the supplied DOM node is a valid node element. * @@ -96,9 +95,9 @@ var DOCUMENT_FRAGMENT_NODE_TYPE = 11; */ function isValidContainer(node) { return !!(node && - (node.nodeType === ELEMENT_NODE_TYPE || - node.nodeType === DOC_NODE_TYPE || - node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)); + (node.nodeType === ELEMENT_NODE || + node.nodeType === DOCUMENT_NODE || + node.nodeType === DOCUMENT_FRAGMENT_NODE)); } function validateContainer(container) { @@ -112,7 +111,7 @@ function getReactRootElementInContainer(container: any) { return null; } - if (container.nodeType === DOC_NODE_TYPE) { + if (container.nodeType === DOCUMENT_NODE) { return container.documentElement; } else { return container.firstChild; diff --git a/src/renderers/dom/fiber/ReactDOMFiberComponent.js b/src/renderers/dom/fiber/ReactDOMFiberComponent.js index 7aea3c569735a..7718b4e89ca9b 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberComponent.js +++ b/src/renderers/dom/fiber/ReactDOMFiberComponent.js @@ -25,6 +25,7 @@ var ReactDOMFiberOption = require('ReactDOMFiberOption'); var ReactDOMFiberSelect = require('ReactDOMFiberSelect'); var ReactDOMFiberTextarea = require('ReactDOMFiberTextarea'); var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber'); +var {DOCUMENT_FRAGMENT_NODE} = require('HTMLNodeType'); var emptyFunction = require('fbjs/lib/emptyFunction'); var invariant = require('fbjs/lib/invariant'); @@ -63,9 +64,6 @@ var { mathml: MATH_NAMESPACE, } = DOMNamespaces; -// Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE). -var DOC_FRAGMENT_TYPE = 11; - function getDeclarationErrorAddendum() { if (__DEV__) { var ownerName = getCurrentFiberOwnerName(); @@ -144,7 +142,8 @@ if (__DEV__) { } function ensureListeningTo(rootContainerElement, registrationName) { - var isDocumentFragment = rootContainerElement.nodeType === DOC_FRAGMENT_TYPE; + var isDocumentFragment = rootContainerElement.nodeType === + DOCUMENT_FRAGMENT_NODE; var doc = isDocumentFragment ? rootContainerElement : rootContainerElement.ownerDocument; diff --git a/src/renderers/dom/shared/HTMLNodeType.js b/src/renderers/dom/shared/HTMLNodeType.js new file mode 100644 index 0000000000000..35566be173211 --- /dev/null +++ b/src/renderers/dom/shared/HTMLNodeType.js @@ -0,0 +1,26 @@ +/** + * 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 HTMLNodeType + */ + +'use strict'; + +/** + * HTML nodeType values that represent the type of the node + */ + +var HTMLNodeType = { + ELEMENT_NODE: 1, + TEXT_NODE: 3, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_FRAGMENT_NODE: 11, +}; + +module.exports = HTMLNodeType; diff --git a/src/renderers/dom/shared/ReactDOMComponentTree.js b/src/renderers/dom/shared/ReactDOMComponentTree.js index 600188f0951a3..978d60d51ec8d 100644 --- a/src/renderers/dom/shared/ReactDOMComponentTree.js +++ b/src/renderers/dom/shared/ReactDOMComponentTree.js @@ -14,6 +14,7 @@ var DOMProperty = require('DOMProperty'); var ReactDOMComponentFlags = require('ReactDOMComponentFlags'); var {HostComponent, HostText} = require('ReactTypeOfWork'); +var {ELEMENT_NODE, COMMENT_NODE} = require('HTMLNodeType'); var invariant = require('fbjs/lib/invariant'); @@ -30,11 +31,12 @@ var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; * Check if a given node should be cached. */ function shouldPrecacheNode(node, nodeID) { - return (node.nodeType === 1 && + return (node.nodeType === ELEMENT_NODE && node.getAttribute(ATTR_NAME) === '' + nodeID) || - (node.nodeType === 8 && + (node.nodeType === COMMENT_NODE && node.nodeValue === ' react-text: ' + nodeID + ' ') || - (node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' '); + (node.nodeType === COMMENT_NODE && + node.nodeValue === ' react-empty: ' + nodeID + ' '); } /** diff --git a/src/renderers/dom/shared/ReactInputSelection.js b/src/renderers/dom/shared/ReactInputSelection.js index dae4085f6a78a..2fd94d4ef0e05 100644 --- a/src/renderers/dom/shared/ReactInputSelection.js +++ b/src/renderers/dom/shared/ReactInputSelection.js @@ -12,6 +12,7 @@ 'use strict'; var ReactDOMSelection = require('ReactDOMSelection'); +var {ELEMENT_NODE} = require('HTMLNodeType'); var containsNode = require('fbjs/lib/containsNode'); var focusNode = require('fbjs/lib/focusNode'); @@ -64,7 +65,7 @@ var ReactInputSelection = { const ancestors = []; let ancestor = priorFocusedElem; while ((ancestor = ancestor.parentNode)) { - if (ancestor.nodeType === 1) { + if (ancestor.nodeType === ELEMENT_NODE) { ancestors.push({ element: ancestor, left: ancestor.scrollLeft, diff --git a/src/renderers/dom/shared/eventPlugins/SelectEventPlugin.js b/src/renderers/dom/shared/eventPlugins/SelectEventPlugin.js index 1989139b1a0e5..c075529e21c5e 100644 --- a/src/renderers/dom/shared/eventPlugins/SelectEventPlugin.js +++ b/src/renderers/dom/shared/eventPlugins/SelectEventPlugin.js @@ -17,6 +17,7 @@ var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactInputSelection = require('ReactInputSelection'); var SyntheticEvent = require('SyntheticEvent'); +var {DOCUMENT_NODE} = require('HTMLNodeType'); var getActiveElement = require('fbjs/lib/getActiveElement'); var isTextInputElement = require('isTextInputElement'); @@ -148,7 +149,7 @@ var SelectEventPlugin = { ) { var doc = nativeEventTarget.window === nativeEventTarget ? nativeEventTarget.document - : nativeEventTarget.nodeType === 9 + : nativeEventTarget.nodeType === DOCUMENT_NODE ? nativeEventTarget : nativeEventTarget.ownerDocument; if (!doc || !isListeningToAllDependencies('onSelect', doc)) { diff --git a/src/renderers/dom/shared/findDOMNode.js b/src/renderers/dom/shared/findDOMNode.js index 35aa38518dd29..1374e320a6b31 100644 --- a/src/renderers/dom/shared/findDOMNode.js +++ b/src/renderers/dom/shared/findDOMNode.js @@ -11,6 +11,7 @@ */ var ReactInstanceMap = require('ReactInstanceMap'); +var {ELEMENT_NODE} = require('HTMLNodeType'); var {ReactCurrentOwner} = require('ReactGlobalSharedState'); var getComponentName = require('getComponentName'); @@ -53,7 +54,7 @@ const findDOMNode = function( if (componentOrElement == null) { return null; } - if ((componentOrElement: any).nodeType === 1) { + if ((componentOrElement: any).nodeType === ELEMENT_NODE) { return (componentOrElement: any); } diff --git a/src/renderers/dom/shared/setTextContent.js b/src/renderers/dom/shared/setTextContent.js index 64db36c40b40d..cef8fbc78e947 100644 --- a/src/renderers/dom/shared/setTextContent.js +++ b/src/renderers/dom/shared/setTextContent.js @@ -14,6 +14,7 @@ var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); var setInnerHTML = require('setInnerHTML'); +var {TEXT_NODE} = require('HTMLNodeType'); /** * Set the textContent property of a node, ensuring that whitespace is preserved @@ -30,7 +31,9 @@ var setTextContent = function(node, text) { var firstChild = node.firstChild; if ( - firstChild && firstChild === node.lastChild && firstChild.nodeType === 3 + firstChild && + firstChild === node.lastChild && + firstChild.nodeType === TEXT_NODE ) { firstChild.nodeValue = text; return; @@ -42,7 +45,7 @@ var setTextContent = function(node, text) { if (ExecutionEnvironment.canUseDOM) { if (!('textContent' in document.documentElement)) { setTextContent = function(node, text) { - if (node.nodeType === 3) { + if (node.nodeType === TEXT_NODE) { node.nodeValue = text; return; } diff --git a/src/renderers/dom/shared/utils/getEventTarget.js b/src/renderers/dom/shared/utils/getEventTarget.js index 83bd08b2a2558..bcd806aec48c2 100644 --- a/src/renderers/dom/shared/utils/getEventTarget.js +++ b/src/renderers/dom/shared/utils/getEventTarget.js @@ -11,6 +11,8 @@ 'use strict'; +var {TEXT_NODE} = require('HTMLNodeType'); + /** * Gets the target node from a native browser event by accounting for * inconsistencies in browser DOM APIs. @@ -28,7 +30,7 @@ function getEventTarget(nativeEvent) { // Safari may fire events on text nodes (Node.TEXT_NODE is 3). // @see http://www.quirksmode.org/js/events_properties.html - return target.nodeType === 3 ? target.parentNode : target; + return target.nodeType === TEXT_NODE ? target.parentNode : target; } module.exports = getEventTarget; diff --git a/src/renderers/dom/shared/utils/getNodeForCharacterOffset.js b/src/renderers/dom/shared/utils/getNodeForCharacterOffset.js index 65d3a33a91b6d..4a300293f91a9 100644 --- a/src/renderers/dom/shared/utils/getNodeForCharacterOffset.js +++ b/src/renderers/dom/shared/utils/getNodeForCharacterOffset.js @@ -11,6 +11,8 @@ 'use strict'; +var {TEXT_NODE} = require('HTMLNodeType'); + /** * Given any node return the first leaf node without children. * @@ -53,7 +55,7 @@ function getNodeForCharacterOffset(root, offset) { var nodeEnd = 0; while (node) { - if (node.nodeType === 3) { + if (node.nodeType === TEXT_NODE) { nodeEnd = nodeStart + node.textContent.length; if (nodeStart <= offset && nodeEnd >= offset) { diff --git a/src/renderers/dom/stack/client/DOMLazyTree.js b/src/renderers/dom/stack/client/DOMLazyTree.js index 7d5b6bb1b649e..a6ef556d5e836 100644 --- a/src/renderers/dom/stack/client/DOMLazyTree.js +++ b/src/renderers/dom/stack/client/DOMLazyTree.js @@ -13,13 +13,10 @@ var DOMNamespaces = require('DOMNamespaces'); var setInnerHTML = require('setInnerHTML'); - +var {DOCUMENT_FRAGMENT_NODE, ELEMENT_NODE} = require('HTMLNodeType'); var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction'); var setTextContent = require('setTextContent'); -var ELEMENT_NODE_TYPE = 1; -var DOCUMENT_FRAGMENT_NODE_TYPE = 11; - /** * In IE (8-11) and Edge, appending nodes with no children is dramatically * faster than appending a full subtree, so we essentially queue up the @@ -63,8 +60,8 @@ var insertTreeBefore = createMicrosoftUnsafeLocalFunction( // nodes immediately upon insertion into the DOM, so // must also be populated prior to insertion into the DOM. if ( - tree.node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE || - (tree.node.nodeType === ELEMENT_NODE_TYPE && + tree.node.nodeType === DOCUMENT_FRAGMENT_NODE || + (tree.node.nodeType === ELEMENT_NODE && tree.node.nodeName.toLowerCase() === 'object' && (tree.node.namespaceURI == null || tree.node.namespaceURI === DOMNamespaces.html)) diff --git a/src/renderers/dom/stack/client/ReactDOMComponent.js b/src/renderers/dom/stack/client/ReactDOMComponent.js index 35e54f7b4efe8..8b2e144e9c24a 100644 --- a/src/renderers/dom/stack/client/ReactDOMComponent.js +++ b/src/renderers/dom/stack/client/ReactDOMComponent.js @@ -30,6 +30,7 @@ var ReactDOMTextarea = require('ReactDOMTextarea'); var ReactInstrumentation = require('ReactInstrumentation'); var ReactMultiChild = require('ReactMultiChild'); var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction'); +var {DOCUMENT_FRAGMENT_NODE} = require('HTMLNodeType'); var emptyFunction = require('fbjs/lib/emptyFunction'); var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); @@ -55,9 +56,6 @@ var RESERVED_PROPS = { suppressContentEditableWarning: null, }; -// Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE). -var DOC_FRAGMENT_TYPE = 11; - function getDeclarationErrorAddendum(internalInstance) { if (internalInstance) { var owner = internalInstance._currentElement._owner || null; @@ -139,7 +137,7 @@ function ensureListeningTo(inst, registrationName, transaction) { } var containerInfo = inst._hostContainerInfo; var isDocumentFragment = containerInfo._node && - containerInfo._node.nodeType === DOC_FRAGMENT_TYPE; + containerInfo._node.nodeType === DOCUMENT_FRAGMENT_NODE; var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument; diff --git a/src/renderers/dom/stack/client/ReactDOMContainerInfo.js b/src/renderers/dom/stack/client/ReactDOMContainerInfo.js index 263c42c7645d7..2e525014b46fb 100644 --- a/src/renderers/dom/stack/client/ReactDOMContainerInfo.js +++ b/src/renderers/dom/stack/client/ReactDOMContainerInfo.js @@ -12,15 +12,14 @@ 'use strict'; var validateDOMNesting = require('validateDOMNesting'); - -var DOC_NODE_TYPE = 9; +var {DOCUMENT_NODE} = require('HTMLNodeType'); function ReactDOMContainerInfo(topLevelWrapper, node) { var info = { _topLevelWrapper: topLevelWrapper, _idCounter: 1, _ownerDocument: node - ? node.nodeType === DOC_NODE_TYPE ? node : node.ownerDocument + ? node.nodeType === DOCUMENT_NODE ? node : node.ownerDocument : null, _node: node, _tag: node ? node.nodeName.toLowerCase() : null, diff --git a/src/renderers/dom/stack/client/ReactDOMTextComponent.js b/src/renderers/dom/stack/client/ReactDOMTextComponent.js index 3ff3a47f92786..55a943d1a9886 100644 --- a/src/renderers/dom/stack/client/ReactDOMTextComponent.js +++ b/src/renderers/dom/stack/client/ReactDOMTextComponent.js @@ -14,6 +14,7 @@ var DOMChildrenOperations = require('DOMChildrenOperations'); var DOMLazyTree = require('DOMLazyTree'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); +var {COMMENT_NODE} = require('HTMLNodeType'); var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); var invariant = require('fbjs/lib/invariant'); @@ -159,7 +160,9 @@ Object.assign(ReactDOMTextComponent.prototype, { 'Missing closing comment for text component %s', this._domID, ); - if (node.nodeType === 8 && node.nodeValue === ' /react-text ') { + if ( + node.nodeType === COMMENT_NODE && node.nodeValue === ' /react-text ' + ) { this._closingComment = node; break; } diff --git a/src/renderers/dom/stack/client/ReactMount.js b/src/renderers/dom/stack/client/ReactMount.js index 9cbc2c91e44ed..2f567b8367daa 100644 --- a/src/renderers/dom/stack/client/ReactMount.js +++ b/src/renderers/dom/stack/client/ReactMount.js @@ -33,14 +33,15 @@ var setInnerHTML = require('setInnerHTML'); var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); var warning = require('fbjs/lib/warning'); var validateCallback = require('validateCallback'); +var { + DOCUMENT_NODE, + ELEMENT_NODE, + DOCUMENT_FRAGMENT_NODE, +} = require('HTMLNodeType'); var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; var ROOT_ATTR_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; -var ELEMENT_NODE_TYPE = 1; -var DOC_NODE_TYPE = 9; -var DOCUMENT_FRAGMENT_NODE_TYPE = 11; - var instancesByReactRootID = {}; /** @@ -69,7 +70,7 @@ function getReactRootElementInContainer(container) { return null; } - if (container.nodeType === DOC_NODE_TYPE) { + if (container.nodeType === DOCUMENT_NODE) { return container.documentElement; } else { return container.firstChild; @@ -181,7 +182,7 @@ function unmountComponentFromNode(instance, container) { ReactInstrumentation.debugTool.onEndFlush(); } - if (container.nodeType === DOC_NODE_TYPE) { + if (container.nodeType === DOCUMENT_NODE) { container = container.documentElement; } @@ -233,9 +234,9 @@ function nodeIsRenderedByOtherInstance(container) { */ function isValidContainer(node) { return !!(node && - (node.nodeType === ELEMENT_NODE_TYPE || - node.nodeType === DOC_NODE_TYPE || - node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)); + (node.nodeType === ELEMENT_NODE || + node.nodeType === DOCUMENT_NODE || + node.nodeType === DOCUMENT_FRAGMENT_NODE)); } /** @@ -638,7 +639,7 @@ var ReactMount = { var containerHasNonRootReactChild = hasNonRootReactChild(container); // Check if the container itself is a React root node. - var isContainerReactRoot = container.nodeType === 1 && + var isContainerReactRoot = container.nodeType === ELEMENT_NODE && container.hasAttribute(ROOT_ATTR_NAME); if (__DEV__) { @@ -701,7 +702,7 @@ var ReactMount = { // insert markup into a
    or