diff --git a/fixtures/README.md b/fixtures/README.md new file mode 100644 index 0000000000..0c9646ce4d --- /dev/null +++ b/fixtures/README.md @@ -0,0 +1,50 @@ +# Manual Testing Fixtures + +This folder exists for **React contributors** only. +If you use React you don't need to worry about it. + +These fixtures verify that the built React distributions are usable in different environments. +**They are not running automatically.** (At least not yet, feel free to contribute to automate them.) + +Run them when you make changes to how we package React, ReactDOM, and addons. + +## How to Run + +First, build React and the fixtures: + +``` +cd react +npm run build + +cd fixtures +node build-all.js +``` + +Then run a local server at the root of the repo, e.g. + +``` +npm i -g pushstate-server +cd .. +pushstate-server . +``` + +(Too complicated? Send a PR to simplify this :-). + +Then open the corresponding URLs, for example: + +``` +open http://localhost:9000/fixtures/globals.html +open http://localhost:9000/fixtures/requirejs.html +open http://localhost:9000/fixtures/systemjs.html +open http://localhost:9000/fixtures/browserify/index.html +open http://localhost:9000/fixtures/brunch/index.html +open http://localhost:9000/fixtures/rjs/index.html +open http://localhost:9000/fixtures/systemjs-builder/index.html +open http://localhost:9000/fixtures/webpack/index.html +open http://localhost:9000/fixtures/webpack-alias/index.html +``` + +You should see two things: + +* "Hello World" fading in with an animation. +* No errors in the console. diff --git a/fixtures/browserify/.gitignore b/fixtures/browserify/.gitignore new file mode 100644 index 0000000000..66b00e6a05 --- /dev/null +++ b/fixtures/browserify/.gitignore @@ -0,0 +1 @@ +output.js diff --git a/fixtures/browserify/index.html b/fixtures/browserify/index.html new file mode 100644 index 0000000000..d2b798e524 --- /dev/null +++ b/fixtures/browserify/index.html @@ -0,0 +1,16 @@ + + + +
+ + + \ No newline at end of file diff --git a/fixtures/browserify/input.js b/fixtures/browserify/input.js new file mode 100644 index 0000000000..da6cc5d0ff --- /dev/null +++ b/fixtures/browserify/input.js @@ -0,0 +1,16 @@ +var React = require('react'); +var CSSTransitionGroup = require('react-addons-css-transition-group'); +var ReactDOM = require('react-dom'); + +ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') +); diff --git a/fixtures/browserify/package.json b/fixtures/browserify/package.json new file mode 100644 index 0000000000..dbcf1dd834 --- /dev/null +++ b/fixtures/browserify/package.json @@ -0,0 +1,10 @@ +{ + "name": "webpack-test", + "private": true, + "dependencies": { + "browserify": "^13.3.0" + }, + "scripts": { + "build": "rm -f output.js && NODE_PATH=../../build/packages browserify ./input.js -o output.js" + } +} diff --git a/fixtures/brunch/.gitignore b/fixtures/brunch/.gitignore new file mode 100644 index 0000000000..b8d1dfad58 --- /dev/null +++ b/fixtures/brunch/.gitignore @@ -0,0 +1,2 @@ +output.js +output.js.map \ No newline at end of file diff --git a/fixtures/brunch/app/initialize.js b/fixtures/brunch/app/initialize.js new file mode 100644 index 0000000000..da6cc5d0ff --- /dev/null +++ b/fixtures/brunch/app/initialize.js @@ -0,0 +1,16 @@ +var React = require('react'); +var CSSTransitionGroup = require('react-addons-css-transition-group'); +var ReactDOM = require('react-dom'); + +ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') +); diff --git a/fixtures/brunch/config.js b/fixtures/brunch/config.js new file mode 100644 index 0000000000..ba12fc72c2 --- /dev/null +++ b/fixtures/brunch/config.js @@ -0,0 +1,10 @@ +exports.config = { + paths: { + public: '.', + }, + files: { + javascripts: { + joinTo: 'output.js', + }, + }, +}; diff --git a/fixtures/brunch/index.html b/fixtures/brunch/index.html new file mode 100644 index 0000000000..859d98d0f2 --- /dev/null +++ b/fixtures/brunch/index.html @@ -0,0 +1,17 @@ + + + +
+ + + + \ No newline at end of file diff --git a/fixtures/brunch/input.js b/fixtures/brunch/input.js new file mode 100644 index 0000000000..da6cc5d0ff --- /dev/null +++ b/fixtures/brunch/input.js @@ -0,0 +1,16 @@ +var React = require('react'); +var CSSTransitionGroup = require('react-addons-css-transition-group'); +var ReactDOM = require('react-dom'); + +ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') +); diff --git a/fixtures/brunch/package.json b/fixtures/brunch/package.json new file mode 100644 index 0000000000..d00bcc0ef0 --- /dev/null +++ b/fixtures/brunch/package.json @@ -0,0 +1,10 @@ +{ + "name": "brunch-test", + "devDependencies": { + "brunch": "^2.9.1", + "javascript-brunch": "^2.0.0" + }, + "scripts": { + "build": "rm -rf public && ln -fs ../../../build/packages/react node_modules/react && ln -fs ../../../build/packages/react-dom node_modules/react-dom && ln -fs ../../../build/packages/react-addons-css-transition-group node_modules/react-addons-css-transition-group && brunch build" + } +} \ No newline at end of file diff --git a/fixtures/build-all.js b/fixtures/build-all.js new file mode 100644 index 0000000000..b5620c0fa3 --- /dev/null +++ b/fixtures/build-all.js @@ -0,0 +1,30 @@ +var fs = require('fs'); +var path = require('path'); +var { spawnSync } = require('child_process'); + +var fixtureDirs = fs.readdirSync(__dirname).filter((file) => { + return fs.statSync(path.join(__dirname, file)).isDirectory(); +}); + +var cmdArgs = [ + {cmd: 'npm', args: ['install']}, + {cmd: 'npm', args: ['run', 'build']}, +]; + +for (const dir of fixtureDirs) { + for (const cmdArg of cmdArgs) { + const opts = { + cwd: path.join(__dirname, dir), + stdio: 'inherit', + }; + let result = spawnSync(cmdArg.cmd, cmdArg.args, opts); + if (result.status !== 0) { + throw new Error('Failed to build fixtures.'); + } + } +} + +console.log('-------------------------'); +console.log('All fixtures were built!'); +console.log('Now make sure to open each HTML file in this directory and each index.html in subdirectories.'); +console.log('-------------------------'); diff --git a/fixtures/globals.html b/fixtures/globals.html new file mode 100644 index 0000000000..c3a7da3c59 --- /dev/null +++ b/fixtures/globals.html @@ -0,0 +1,32 @@ + + + + + +
+ + + \ No newline at end of file diff --git a/fixtures/requirejs.html b/fixtures/requirejs.html new file mode 100644 index 0000000000..c2ff2338a3 --- /dev/null +++ b/fixtures/requirejs.html @@ -0,0 +1,40 @@ + + + + +
+ + + \ No newline at end of file diff --git a/fixtures/rjs/.gitignore b/fixtures/rjs/.gitignore new file mode 100644 index 0000000000..fa213fe698 --- /dev/null +++ b/fixtures/rjs/.gitignore @@ -0,0 +1 @@ +output.js \ No newline at end of file diff --git a/fixtures/rjs/config.js b/fixtures/rjs/config.js new file mode 100644 index 0000000000..f15dc11003 --- /dev/null +++ b/fixtures/rjs/config.js @@ -0,0 +1,10 @@ +module.exports = { + baseUrl: '.', + name: 'input', + out: 'output.js', + optimize: 'none', + paths: { + react: '../../build/react-with-addons', + 'react-dom': '../../build/react-dom', + }, +}; diff --git a/fixtures/rjs/index.html b/fixtures/rjs/index.html new file mode 100644 index 0000000000..24995379a1 --- /dev/null +++ b/fixtures/rjs/index.html @@ -0,0 +1,17 @@ + + + +
+ + + + \ No newline at end of file diff --git a/fixtures/rjs/input.js b/fixtures/rjs/input.js new file mode 100644 index 0000000000..2b0deee96c --- /dev/null +++ b/fixtures/rjs/input.js @@ -0,0 +1,15 @@ +require(['react', 'react-dom'], function(React, ReactDOM) { + var CSSTransitionGroup = React.addons.CSSTransitionGroup; + ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') + ); +}); diff --git a/fixtures/rjs/package.json b/fixtures/rjs/package.json new file mode 100644 index 0000000000..bc94a37011 --- /dev/null +++ b/fixtures/rjs/package.json @@ -0,0 +1,10 @@ +{ + "name": "rjs-test", + "private": true, + "dependencies": { + "requirejs": "^2.3.2" + }, + "scripts": { + "build": "rm -f output.js && r.js -o config.js" + } +} diff --git a/fixtures/systemjs-builder/.gitignore b/fixtures/systemjs-builder/.gitignore new file mode 100644 index 0000000000..fa213fe698 --- /dev/null +++ b/fixtures/systemjs-builder/.gitignore @@ -0,0 +1 @@ +output.js \ No newline at end of file diff --git a/fixtures/systemjs-builder/build.js b/fixtures/systemjs-builder/build.js new file mode 100644 index 0000000000..d476c09a64 --- /dev/null +++ b/fixtures/systemjs-builder/build.js @@ -0,0 +1,12 @@ +var Builder = require('systemjs-builder'); + +var builder = new Builder('/', './config.js'); +builder + .buildStatic('./input.js', './output.js') + .then(function() { + console.log('Build complete'); + }) + .catch(function(err) { + console.log('Build error'); + console.log(err); + }); diff --git a/fixtures/systemjs-builder/config.js b/fixtures/systemjs-builder/config.js new file mode 100644 index 0000000000..baed2db8c6 --- /dev/null +++ b/fixtures/systemjs-builder/config.js @@ -0,0 +1,6 @@ +System.config({ + paths: { + react: '../../build/react-with-addons.js', + 'react-dom': '../../build/react-dom.js', + }, +}); diff --git a/fixtures/systemjs-builder/index.html b/fixtures/systemjs-builder/index.html new file mode 100644 index 0000000000..d2b798e524 --- /dev/null +++ b/fixtures/systemjs-builder/index.html @@ -0,0 +1,16 @@ + + + +
+ + + \ No newline at end of file diff --git a/fixtures/systemjs-builder/input.js b/fixtures/systemjs-builder/input.js new file mode 100644 index 0000000000..27d5c10086 --- /dev/null +++ b/fixtures/systemjs-builder/input.js @@ -0,0 +1,16 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +var CSSTransitionGroup = React.addons.CSSTransitionGroup; +ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') +); diff --git a/fixtures/systemjs-builder/package.json b/fixtures/systemjs-builder/package.json new file mode 100644 index 0000000000..b4c6acdcca --- /dev/null +++ b/fixtures/systemjs-builder/package.json @@ -0,0 +1,10 @@ +{ + "name": "systemjs-builder-test", + "private": true, + "dependencies": { + "systemjs-builder": "^0.15.34" + }, + "scripts": { + "build": "rm -f output.js && node build.js" + } +} diff --git a/fixtures/systemjs.html b/fixtures/systemjs.html new file mode 100644 index 0000000000..9c4430791c --- /dev/null +++ b/fixtures/systemjs.html @@ -0,0 +1,46 @@ + + + + +
+ + + \ No newline at end of file diff --git a/fixtures/webpack-alias/.gitignore b/fixtures/webpack-alias/.gitignore new file mode 100644 index 0000000000..fa213fe698 --- /dev/null +++ b/fixtures/webpack-alias/.gitignore @@ -0,0 +1 @@ +output.js \ No newline at end of file diff --git a/fixtures/webpack-alias/config.js b/fixtures/webpack-alias/config.js new file mode 100644 index 0000000000..dcc0c3a907 --- /dev/null +++ b/fixtures/webpack-alias/config.js @@ -0,0 +1,13 @@ +module.exports = { + entry: './input', + output: { + filename: 'output.js', + }, + resolve: { + root: '../../build/packages', + alias: { + 'react': 'react/dist/react-with-addons', + 'react-dom': 'react-dom/dist/react-dom', + }, + }, +}; diff --git a/fixtures/webpack-alias/index.html b/fixtures/webpack-alias/index.html new file mode 100644 index 0000000000..d2b798e524 --- /dev/null +++ b/fixtures/webpack-alias/index.html @@ -0,0 +1,16 @@ + + + +
+ + + \ No newline at end of file diff --git a/fixtures/webpack-alias/input.js b/fixtures/webpack-alias/input.js new file mode 100644 index 0000000000..f1e2d79e23 --- /dev/null +++ b/fixtures/webpack-alias/input.js @@ -0,0 +1,16 @@ +var React = require('react'); +var ReactDOM = require('react-dom'); + +var CSSTransitionGroup = React.addons.CSSTransitionGroup; +ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') +); diff --git a/fixtures/webpack-alias/package.json b/fixtures/webpack-alias/package.json new file mode 100644 index 0000000000..8ea2da478b --- /dev/null +++ b/fixtures/webpack-alias/package.json @@ -0,0 +1,10 @@ +{ + "name": "webpack-test", + "private": true, + "dependencies": { + "webpack": "^1.14.0" + }, + "scripts": { + "build": "rm -f output.js && webpack --config config.js" + } +} diff --git a/fixtures/webpack/.gitignore b/fixtures/webpack/.gitignore new file mode 100644 index 0000000000..fa213fe698 --- /dev/null +++ b/fixtures/webpack/.gitignore @@ -0,0 +1 @@ +output.js \ No newline at end of file diff --git a/fixtures/webpack/config.js b/fixtures/webpack/config.js new file mode 100644 index 0000000000..685cac24ee --- /dev/null +++ b/fixtures/webpack/config.js @@ -0,0 +1,9 @@ +module.exports = { + entry: './input', + output: { + filename: 'output.js', + }, + resolve: { + root: '../../build/packages', + }, +}; diff --git a/fixtures/webpack/index.html b/fixtures/webpack/index.html new file mode 100644 index 0000000000..d2b798e524 --- /dev/null +++ b/fixtures/webpack/index.html @@ -0,0 +1,16 @@ + + + +
+ + + \ No newline at end of file diff --git a/fixtures/webpack/input.js b/fixtures/webpack/input.js new file mode 100644 index 0000000000..da6cc5d0ff --- /dev/null +++ b/fixtures/webpack/input.js @@ -0,0 +1,16 @@ +var React = require('react'); +var CSSTransitionGroup = require('react-addons-css-transition-group'); +var ReactDOM = require('react-dom'); + +ReactDOM.render( + React.createElement(CSSTransitionGroup, { + transitionName: 'example', + transitionAppear: true, + transitionAppearTimeout: 500, + transitionEnterTimeout: 0, + transitionLeaveTimeout: 0, + }, React.createElement('h1', null, + 'Hello World!' + )), + document.getElementById('container') +); diff --git a/fixtures/webpack/package.json b/fixtures/webpack/package.json new file mode 100644 index 0000000000..8ea2da478b --- /dev/null +++ b/fixtures/webpack/package.json @@ -0,0 +1,10 @@ +{ + "name": "webpack-test", + "private": true, + "dependencies": { + "webpack": "^1.14.0" + }, + "scripts": { + "build": "rm -f output.js && webpack --config config.js" + } +} diff --git a/packages/react-addons/package.json b/packages/react-addons/package.json index b5744d100d..b82668cc28 100644 --- a/packages/react-addons/package.json +++ b/packages/react-addons/package.json @@ -8,7 +8,10 @@ "react-addon" ], "license": "BSD-3-Clause", - "dependencies": {}, + "dependencies": { + "fbjs": "^0.8.4", + "object-assign": "^4.1.0" + }, "peerDependencies": { "react": "^15.4.1" }, diff --git a/packages/react-test-renderer/package.json b/packages/react-test-renderer/package.json index 218dc8df85..de4ae74d07 100644 --- a/packages/react-test-renderer/package.json +++ b/packages/react-test-renderer/package.json @@ -14,6 +14,10 @@ "url": "https://github.com/facebook/react/issues" }, "homepage": "https://facebook.github.io/react/", + "dependencies": { + "fbjs": "^0.8.4", + "object-assign": "^4.1.0" + }, "peerDependencies": { "react": "^15.4.1" }, diff --git a/src/addons/ReactAddonsDOMDependencies.js b/src/addons/ReactAddonsDOMDependencies.js index e0b5eb45a5..70856ec6c5 100644 --- a/src/addons/ReactAddonsDOMDependencies.js +++ b/src/addons/ReactAddonsDOMDependencies.js @@ -12,25 +12,26 @@ 'use strict'; var ReactDOM = require('ReactDOM'); -var ReactInstanceMap = require('ReactInstanceMap'); exports.getReactDOM = function() { return ReactDOM; }; -exports.getReactInstanceMap = function() { - return ReactInstanceMap; -}; - if (__DEV__) { - var ReactPerf = require('ReactPerf'); - var ReactTestUtils = require('ReactTestUtils'); + var ReactPerf; + var ReactTestUtils; exports.getReactPerf = function() { + if (!ReactPerf) { + ReactPerf = require('ReactPerf'); + } return ReactPerf; }; exports.getReactTestUtils = function() { + if (!ReactTestUtils) { + ReactTestUtils = require('ReactTestUtils'); + } return ReactTestUtils; }; } diff --git a/src/addons/transitions/ReactTransitionGroup.js b/src/addons/transitions/ReactTransitionGroup.js index 001b06fb9d..62372801fa 100644 --- a/src/addons/transitions/ReactTransitionGroup.js +++ b/src/addons/transitions/ReactTransitionGroup.js @@ -12,7 +12,6 @@ 'use strict'; var React = require('React'); -var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies'); var ReactTransitionChildMapping = require('ReactTransitionChildMapping'); var emptyFunction = require('emptyFunction'); @@ -56,17 +55,9 @@ class ReactTransitionGroup extends React.Component { } componentWillReceiveProps(nextProps) { - var nextChildMapping; - if (__DEV__) { - nextChildMapping = ReactTransitionChildMapping.getChildMapping( - nextProps.children, - ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID - ); - } else { - nextChildMapping = ReactTransitionChildMapping.getChildMapping( - nextProps.children - ); - } + var nextChildMapping = ReactTransitionChildMapping.getChildMapping( + nextProps.children + ); var prevChildMapping = this.state.children; this.setState({ @@ -129,17 +120,9 @@ class ReactTransitionGroup extends React.Component { delete this.currentlyTransitioningKeys[key]; - var currentChildMapping; - if (__DEV__) { - currentChildMapping = ReactTransitionChildMapping.getChildMapping( - this.props.children, - ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID - ); - } else { - currentChildMapping = ReactTransitionChildMapping.getChildMapping( - this.props.children - ); - } + var currentChildMapping = ReactTransitionChildMapping.getChildMapping( + this.props.children + ); if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) { // This was removed before it had fully appeared. Remove it. @@ -169,17 +152,9 @@ class ReactTransitionGroup extends React.Component { delete this.currentlyTransitioningKeys[key]; - var currentChildMapping; - if (__DEV__) { - currentChildMapping = ReactTransitionChildMapping.getChildMapping( - this.props.children, - ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID - ); - } else { - currentChildMapping = ReactTransitionChildMapping.getChildMapping( - this.props.children - ); - } + var currentChildMapping = ReactTransitionChildMapping.getChildMapping( + this.props.children + ); if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) { // This was removed before it had fully entered. Remove it. @@ -210,17 +185,9 @@ class ReactTransitionGroup extends React.Component { delete this.currentlyTransitioningKeys[key]; - var currentChildMapping; - if (__DEV__) { - currentChildMapping = ReactTransitionChildMapping.getChildMapping( - this.props.children, - ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID - ); - } else { - currentChildMapping = ReactTransitionChildMapping.getChildMapping( - this.props.children - ); - } + var currentChildMapping = ReactTransitionChildMapping.getChildMapping( + this.props.children + ); if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) { // This entered again before it fully left. Add it again. diff --git a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactTransitionGroup-test.js index 90c0e01900..25e6dfdcd1 100644 --- a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js +++ b/src/addons/transitions/__tests__/ReactTransitionGroup-test.js @@ -20,10 +20,6 @@ var ReactTransitionGroup; describe('ReactTransitionGroup', () => { var container; - function normalizeCodeLocInfo(str) { - return str.replace(/\(at .+?:\d+\)/g, '(at **)'); - } - beforeEach(() => { React = require('React'); ReactDOM = require('ReactDOM'); @@ -296,7 +292,7 @@ describe('ReactTransitionGroup', () => { ]); }); - it('should warn for duplicated keys with component stack info', () => { + it('should warn for duplicated keys', () => { spyOn(console, 'error'); class Component extends React.Component { @@ -315,13 +311,11 @@ describe('ReactTransitionGroup', () => { 'Child keys must be unique; when two children share a key, ' + 'only the first child will be used.' ); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( + expect(console.error.calls.argsFor(1)[0]).toBe( 'Warning: flattenChildren(...): ' + 'Encountered two children with the same key, `1`. ' + 'Child keys must be unique; when two children share a key, ' + - 'only the first child will be used.\n' + - ' in ReactTransitionGroup (at **)\n' + - ' in Component (at **)' + 'only the first child will be used.' ); }); }); diff --git a/src/isomorphic/classic/element/ReactElementValidator.js b/src/isomorphic/classic/element/ReactElementValidator.js index 8c30884017..e7ad9d72a7 100644 --- a/src/isomorphic/classic/element/ReactElementValidator.js +++ b/src/isomorphic/classic/element/ReactElementValidator.js @@ -187,13 +187,31 @@ var ReactElementValidator = { // We warn in this case but don't throw. We expect the element creation to // succeed and there will likely be errors in render. if (!validType) { - warning( - false, - 'React.createElement: type should not be null, undefined, boolean, or ' + - 'number. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components).%s', - getDeclarationErrorAddendum() - ); + if ( + typeof type !== 'function' && + typeof type !== 'string' + ) { + var info = ''; + if ( + type === undefined || + typeof type === 'object' && + type !== null && + Object.keys(type).length === 0 + ) { + info += + ' You likely forgot to export your component from the file ' + + 'it\'s defined in.'; + } + info += getDeclarationErrorAddendum(); + warning( + false, + 'React.createElement: type is invalid -- expected a string (for ' + + 'built-in components) or a class/function (for composite ' + + 'components) but got: %s.%s', + type == null ? type : typeof type, + info, + ); + } } var element = ReactElement.createElement.apply(this, arguments); diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js index 5690e2125b..b36fa2f39c 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js @@ -289,35 +289,49 @@ describe('ReactElementValidator', () => { ); }); - it('gives a helpful error when passing null, undefined, boolean, or number', () => { + it('gives a helpful error when passing invalid types', () => { spyOn(console, 'error'); React.createElement(undefined); React.createElement(null); React.createElement(true); React.createElement(123); - expect(console.error.calls.count()).toBe(4); + React.createElement({x: 17}); + React.createElement({}); + expect(console.error.calls.count()).toBe(6); expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: undefined. You likely forgot to export your ' + + 'component from the file it\'s defined in.' ); expect(console.error.calls.argsFor(1)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: null.' ); expect(console.error.calls.argsFor(2)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: boolean.' ); expect(console.error.calls.argsFor(3)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: number.' + ); + expect(console.error.calls.argsFor(4)[0]).toBe( + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: object.' + ); + expect(console.error.calls.argsFor(5)[0]).toBe( + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: object. You likely forgot to export your ' + + 'component from the file it\'s defined in.' ); React.createElement('div'); - expect(console.error.calls.count()).toBe(4); + expect(console.error.calls.count()).toBe(6); }); it('includes the owner name when passing null, undefined, boolean, or number', () => { @@ -336,10 +350,9 @@ describe('ReactElementValidator', () => { ); expect(console.error.calls.count()).toBe(1); expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components). Check the render method of ' + - '`ParentComp`.' + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: null. Check the render method of `ParentComp`.' ); }); @@ -537,9 +550,10 @@ describe('ReactElementValidator', () => { void {[
]}; expect(console.error.calls.count()).toBe(1); expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: undefined. You likely forgot to export your ' + + 'component from the file it\'s defined in.' ); }); diff --git a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee index cf71005350..de03d875b0 100644 --- a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee @@ -319,6 +319,25 @@ describe 'ReactCoffeeScriptClass', -> ) undefined + it 'does not warn about getInitialState() on class components + if state is also defined.', -> + spyOn console, 'error' + class Foo extends React.Component + constructor: (props) -> + super props + @state = bar: @props.initialValue + + getInitialState: -> + {} + + render: -> + span + className: 'foo' + + test React.createElement(Foo), 'SPAN', 'foo' + expect(console.error.calls.count()).toBe 0 + undefined + it 'should warn when misspelling shouldComponentUpdate', -> spyOn console, 'error' class NamedComponent extends React.Component diff --git a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js index 2ff9091c1a..ca34089157 100644 --- a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js +++ b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js @@ -354,6 +354,21 @@ describe('ReactES6Class', () => { ); }); + it('does not warn about getInitialState() on class components if state is also defined.', () => { + spyOn(console, 'error'); + class Foo extends React.Component { + state = this.getInitialState(); + getInitialState() { + return {}; + } + render() { + return ; + } + } + test(, 'SPAN', 'foo'); + expect(console.error.calls.count()).toBe(0); + }); + it('should warn when misspelling shouldComponentUpdate', () => { spyOn(console, 'error'); diff --git a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts index 0e90be788a..6ef95ccaa3 100644 --- a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts +++ b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts @@ -454,6 +454,24 @@ describe('ReactTypeScriptClass', function() { ); }); + it('does not warn about getInitialState() on class components ' + + 'if state is also defined.', () => { + spyOn(console, 'error'); + + class Example extends React.Component { + state = {}; + getInitialState() { + return {}; + } + render() { + return React.createElement('span', {className: 'foo'}); + } + } + + test(React.createElement(Example), 'SPAN', 'foo'); + expect((console.error).calls.count()).toBe(0); + }); + it('should warn when misspelling shouldComponentUpdate', function() { spyOn(console, 'error'); diff --git a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js index 71fbed5bd3..00f3650217 100644 --- a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js +++ b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js @@ -218,21 +218,26 @@ describe('ReactJSXElementValidator', () => { void ; void ; expect(console.error.calls.count()).toBe(4); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + expect(console.error.calls.argsFor(0)[0]).toBe( + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: undefined. You likely forgot to export your ' + + 'component from the file it\'s defined in.' ); - expect(console.error.calls.argsFor(1)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + expect(console.error.calls.argsFor(1)[0]).toBe( + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: null.' ); - expect(console.error.calls.argsFor(2)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + expect(console.error.calls.argsFor(2)[0]).toBe( + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: boolean.' ); - expect(console.error.calls.argsFor(3)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + expect(console.error.calls.argsFor(3)[0]).toBe( + 'Warning: React.createElement: type is invalid -- expected a string ' + + '(for built-in components) or a class/function (for composite ' + + 'components) but got: number.' ); void
; expect(console.error.calls.count()).toBe(4); diff --git a/src/renderers/dom/client/ReactDOMComponentTree.js b/src/renderers/dom/client/ReactDOMComponentTree.js index 8ff3260e85..d440446ace 100644 --- a/src/renderers/dom/client/ReactDOMComponentTree.js +++ b/src/renderers/dom/client/ReactDOMComponentTree.js @@ -22,6 +22,18 @@ var Flags = ReactDOMComponentFlags; var internalInstanceKey = '__reactInternalInstance$' + Math.random().toString(36).slice(2); +/** + * Check if a given node should be cached. + */ +function shouldPrecacheNode(node, nodeID) { + return (node.nodeType === 1 && + node.getAttribute(ATTR_NAME) === String(nodeID)) || + (node.nodeType === 8 && + node.nodeValue === ' react-text: ' + nodeID + ' ') || + (node.nodeType === 8 && + node.nodeValue === ' react-empty: ' + nodeID + ' '); +} + /** * Drill down (through composites and empty components) until we get a host or * host text component. @@ -87,12 +99,7 @@ function precacheChildNodes(inst, node) { } // We assume the child nodes are in the same order as the child instances. for (; childNode !== null; childNode = childNode.nextSibling) { - if ((childNode.nodeType === 1 && - childNode.getAttribute(ATTR_NAME) === String(childID)) || - (childNode.nodeType === 8 && - childNode.nodeValue === ' react-text: ' + childID + ' ') || - (childNode.nodeType === 8 && - childNode.nodeValue === ' react-empty: ' + childID + ' ')) { + if (shouldPrecacheNode(childNode, childID)) { precacheNode(childInst, childNode); continue outer; } diff --git a/src/renderers/dom/client/wrappers/ReactDOMInput.js b/src/renderers/dom/client/wrappers/ReactDOMInput.js index 04814bd869..8d1ad6ec55 100644 --- a/src/renderers/dom/client/wrappers/ReactDOMInput.js +++ b/src/renderers/dom/client/wrappers/ReactDOMInput.js @@ -213,7 +213,17 @@ var ReactDOMInput = { } } else { if (props.value == null && props.defaultValue != null) { - node.defaultValue = '' + props.defaultValue; + // In Chrome, assigning defaultValue to certain input types triggers input validation. + // For number inputs, the display value loses trailing decimal points. For email inputs, + // Chrome raises "The specified value is not a valid email address". + // + // Here we check to see if the defaultValue has actually changed, avoiding these problems + // when the user is inputting text + // + // https://github.com/facebook/react/issues/7253 + if (node.defaultValue !== '' + props.defaultValue) { + node.defaultValue = '' + props.defaultValue; + } } if (props.checked == null && props.defaultChecked != null) { node.defaultChecked = !!props.defaultChecked; diff --git a/src/renderers/dom/client/wrappers/ReactDOMTextarea.js b/src/renderers/dom/client/wrappers/ReactDOMTextarea.js index faee1b3985..3dbff23a60 100644 --- a/src/renderers/dom/client/wrappers/ReactDOMTextarea.js +++ b/src/renderers/dom/client/wrappers/ReactDOMTextarea.js @@ -167,9 +167,15 @@ var ReactDOMTextarea = { // This is in postMount because we need access to the DOM node, which is not // available until after the component has mounted. var node = ReactDOMComponentTree.getNodeFromInstance(inst); + var textContent = node.textContent; - // Warning: node.value may be the empty string at this point (IE11) if placeholder is set. - node.value = node.textContent; // Detach value from defaultValue + // Only set node.value if textContent is equal to the expected + // initial value. In IE10/IE11 there is a bug where the placeholder attribute + // will populate textContent as well. + // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/ + if (textContent === inst._wrapperState.initialValue) { + node.value = textContent; + } }, }; diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js index 541f0671af..6e387fe3c8 100644 --- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js @@ -42,6 +42,28 @@ describe('ReactDOMInput', () => { expect(node.value).toBe('0'); }); + it('only assigns defaultValue if it changes', () => { + class Test extends React.Component { + render() { + return (); + } + } + + var component = ReactTestUtils.renderIntoDocument(); + var node = ReactDOM.findDOMNode(component); + + Object.defineProperty(node, 'defaultValue', { + get() { + return '0'; + }, + set(value) { + throw new Error(`defaultValue was assigned ${value}, but it did not change!`); + }, + }); + + component.forceUpdate(); + }); + it('should display "true" for `defaultValue` of `true`', () => { var stub = ; stub = ReactTestUtils.renderIntoDocument(stub); diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js index eb56168f25..02759e1e2b 100644 --- a/src/renderers/dom/shared/ReactDOMComponent.js +++ b/src/renderers/dom/shared/ReactDOMComponent.js @@ -828,12 +828,18 @@ ReactDOMComponent.Mixin = { var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null; var childrenToUse = contentToUse != null ? null : props.children; + // TODO: Validate that text is allowed as a child of this node if (contentToUse != null) { - // TODO: Validate that text is allowed as a child of this node - if (__DEV__) { - setAndValidateContentChildDev.call(this, contentToUse); + // Avoid setting textContent when the text is empty. In IE11 setting + // textContent on a text area will cause the placeholder to not + // show within the textarea until it has been focused and blurred again. + // https://github.com/facebook/react/issues/6731#issuecomment-254874553 + if (contentToUse !== '') { + if (__DEV__) { + setAndValidateContentChildDev.call(this, contentToUse); + } + DOMLazyTree.queueText(lazyTree, contentToUse); } - DOMLazyTree.queueText(lazyTree, contentToUse); } else if (childrenToUse != null) { var mountImages = this.mountChildren( childrenToUse, diff --git a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js index 388111d90e..c0bd59c5f6 100644 --- a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js @@ -270,7 +270,8 @@ var ReactCompositeComponent = { // catch them here, at initialization time, instead. warning( !inst.getInitialState || - inst.getInitialState.isReactClassApproved, + inst.getInitialState.isReactClassApproved || + inst.state, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', diff --git a/src/renderers/shared/stack/reconciler/ReactHostComponent.js b/src/renderers/shared/stack/reconciler/ReactHostComponent.js index 7a08f562d7..eebe5cba46 100644 --- a/src/renderers/shared/stack/reconciler/ReactHostComponent.js +++ b/src/renderers/shared/stack/reconciler/ReactHostComponent.js @@ -14,8 +14,6 @@ var invariant = require('invariant'); var genericComponentClass = null; -// This registry keeps track of wrapper classes around host tags. -var tagToComponentClass = {}; var textComponentClass = null; var ReactHostComponentInjection = { @@ -29,11 +27,6 @@ var ReactHostComponentInjection = { injectTextComponentClass: function(componentClass) { textComponentClass = componentClass; }, - // This accepts a keyed object with classes as values. Each key represents a - // tag. That particular tag will use this class instead of the generic one. - injectComponentClasses: function(componentClasses) { - Object.assign(tagToComponentClass, componentClasses); - }, }; /** diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js index 769b2bafcc..28c914152b 100644 --- a/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js +++ b/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js @@ -327,7 +327,9 @@ describe('ReactComponent', () => { var X = undefined; expect(() => ReactTestUtils.renderIntoDocument()).toThrowError( 'Element type is invalid: expected a string (for built-in components) ' + - 'or a class/function (for composite components) but got: undefined.' + 'or a class/function (for composite components) but got: undefined. ' + + 'You likely forgot to export your component from the file it\'s ' + + 'defined in.' ); var Y = null; @@ -340,4 +342,23 @@ describe('ReactComponent', () => { expect(console.error.calls.count()).toBe(2); }); + it('includes owner name in the error about badly-typed elements', () => { + spyOn(console, 'error'); + + function Foo() { + var X = undefined; + return ; + } + + expect(() => ReactTestUtils.renderIntoDocument()).toThrowError( + 'Element type is invalid: expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: undefined. ' + + 'You likely forgot to export your component from the file it\'s ' + + 'defined in. Check the render method of `Foo`.' + ); + + // One warning for each element creation + expect(console.error.calls.count()).toBe(1); + }); + }); diff --git a/src/renderers/shared/stack/reconciler/instantiateReactComponent.js b/src/renderers/shared/stack/reconciler/instantiateReactComponent.js index 202768d8bb..d1b5c23262 100644 --- a/src/renderers/shared/stack/reconciler/instantiateReactComponent.js +++ b/src/renderers/shared/stack/reconciler/instantiateReactComponent.js @@ -72,14 +72,33 @@ function instantiateReactComponent(node, shouldHaveDebugID) { instance = ReactEmptyComponent.create(instantiateReactComponent); } else if (typeof node === 'object') { var element = node; - invariant( - element && (typeof element.type === 'function' || - typeof element.type === 'string'), - 'Element type is invalid: expected a string (for built-in components) ' + - 'or a class/function (for composite components) but got: %s.%s', - element.type == null ? element.type : typeof element.type, - getDeclarationErrorAddendum(element._owner) - ); + var type = element.type; + if ( + typeof type !== 'function' && + typeof type !== 'string' + ) { + var info = ''; + if (__DEV__) { + if ( + type === undefined || + typeof type === 'object' && + type !== null && + Object.keys(type).length === 0 + ) { + info += + ' You likely forgot to export your component from the file ' + + 'it\'s defined in.'; + } + } + info += getDeclarationErrorAddendum(element._owner); + invariant( + false, + 'Element type is invalid: expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: %s.%s', + type == null ? type : typeof type, + info, + ); + } // Special case string values if (typeof element.type === 'string') { diff --git a/src/shared/utils/PooledClass.js b/src/shared/utils/PooledClass.js index 45040901ff..f2d0fc38d5 100644 --- a/src/shared/utils/PooledClass.js +++ b/src/shared/utils/PooledClass.js @@ -65,17 +65,6 @@ var fourArgumentPooler = function(a1, a2, a3, a4) { } }; -var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { - var Klass = this; - if (Klass.instancePool.length) { - var instance = Klass.instancePool.pop(); - Klass.call(instance, a1, a2, a3, a4, a5); - return instance; - } else { - return new Klass(a1, a2, a3, a4, a5); - } -}; - var standardReleaser = function(instance) { var Klass = this; invariant( @@ -127,7 +116,6 @@ var PooledClass = { twoArgumentPooler: (twoArgumentPooler: Pooler), threeArgumentPooler: (threeArgumentPooler: Pooler), fourArgumentPooler: (fourArgumentPooler: Pooler), - fiveArgumentPooler: (fiveArgumentPooler: Pooler), }; module.exports = PooledClass; diff --git a/src/umd/ReactDOMUMDEntry.js b/src/umd/ReactDOMUMDEntry.js index 59daf4bef9..03a0318a10 100644 --- a/src/umd/ReactDOMUMDEntry.js +++ b/src/umd/ReactDOMUMDEntry.js @@ -11,24 +11,24 @@ 'use strict'; +var React = require('React'); var ReactDOM = require('ReactDOM'); -var ReactDOMUMDEntry = Object.assign({ - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - ReactInstanceMap: require('ReactInstanceMap'), - }, -}, ReactDOM); +var ReactDOMUMDEntry = ReactDOM; if (__DEV__) { - Object.assign( - ReactDOMUMDEntry.__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('ReactPerf'), - ReactTestUtils: require('ReactTestUtils'), - } - ); + ReactDOMUMDEntry.__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('ReactPerf'), + ReactTestUtils: require('ReactTestUtils'), + }; +} + +// Inject ReactDOM into React for the addons UMD build that depends on ReactDOM (TransitionGroup). +// We can remove this after we deprecate and remove the addons UMD build. +if (React.addons) { + React.__SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOMUMDEntry; } module.exports = ReactDOMUMDEntry; diff --git a/src/umd/ReactWithAddonsUMDEntry.js b/src/umd/ReactWithAddonsUMDEntry.js index ad05b565c9..c59e62e731 100644 --- a/src/umd/ReactWithAddonsUMDEntry.js +++ b/src/umd/ReactWithAddonsUMDEntry.js @@ -15,6 +15,7 @@ var ReactWithAddons = require('ReactWithAddons'); // `version` will be added here by the React module. var ReactWithAddonsUMDEntry = Object.assign({ + __SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: null, // Will be injected by ReactDOM UMD build. __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { ReactCurrentOwner: require('ReactCurrentOwner'), }, diff --git a/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js b/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js index 2aa7b886b5..f4c06de045 100644 --- a/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js +++ b/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js @@ -9,24 +9,28 @@ * @providesModule ReactAddonsDOMDependenciesUMDShim */ -/* globals ReactDOM */ - 'use strict'; -exports.getReactDOM = function() { - return ReactDOM; -}; +var ReactDOM; -exports.getReactInstanceMap = function() { - return ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactInstanceMap; -}; +function getReactDOM() { + if (!ReactDOM) { + // This is safe to use because current module only exists in the addons build: + var ReactWithAddonsUMDEntry = require('ReactWithAddonsUMDEntry'); + // This is injected by the ReactDOM UMD build: + ReactDOM = ReactWithAddonsUMDEntry.__SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + } + return ReactDOM; +} + +exports.getReactDOM = getReactDOM; if (__DEV__) { exports.getReactPerf = function() { - return ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactPerf; + return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactPerf; }; exports.getReactTestUtils = function() { - return ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactTestUtils; + return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactTestUtils; }; }