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/README.md b/README.md
index df717360fee9a..2ae261c6994a9 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
@@ -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
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..7c38475c1a483
--- /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
;
+ }
+}
+
+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))
diff --git a/docs/community/conferences.md b/docs/community/conferences.md
index f16f7650a598a..fdb7fdb25f881 100644
--- a/docs/community/conferences.md
+++ b/docs/community/conferences.md
@@ -14,16 +14,16 @@ March 28th at the [QEII Centre, London](http://qeiicentre.london/)
[Website](http://react.london/)
-### ReactEurope 2017
-May 18th & 19th in Paris, France
-
-[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule)
-
### React Amsterdam 2017
April 21st in Amsterdam, The Netherlands
[Website](https://react.amsterdam) - [Twitter](https://twitter.com/reactamsterdam)
+### ReactEurope 2017
+May 18th & 19th in Paris, France
+
+[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule)
+
### Chain React 2017
July 10-11 in Portland, Oregon USA
@@ -34,6 +34,11 @@ August 24-25 in Salt Lake City, Utah USA
[Website](http://www.reactrally.com) - [Twitter](https://twitter.com/reactrally)
+### React Native EU 2017
+September 6-7 in Wroclaw, Poland
+
+[Website](http://react-native.eu/)
+
### ReactJS Day 2017
October 6th in Verona, Italy
@@ -44,11 +49,6 @@ October 13 in Stockholm, Sweden
[Website](https://statejs.com/)
-### React Native EU 2017
-September 6-7 in Wroclaw, Poland
-
-[Website](http://react-native.eu/)
-
## Past Conferences
diff --git a/docs/contributing/codebase-overview.md b/docs/contributing/codebase-overview.md
index 045f2c9030231..b9be535b416bc 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.
@@ -302,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.
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.
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
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.
diff --git a/docs/docs/installation.md b/docs/docs/installation.md
index d4ee06ae54422..3072d7768e7eb 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.
+
+
+
+
## 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,69 @@ 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
diff --git a/docs/docs/jsx-in-depth.md b/docs/docs/jsx-in-depth.md
index 41c3813dd8459..d75fd72fc4f4d 100644
--- a/docs/docs/jsx-in-depth.md
+++ b/docs/docs/jsx-in-depth.md
@@ -152,7 +152,7 @@ function Story(props) {
To fix this, we will assign the type to a capitalized variable first:
-```js{9-11}
+```js{10-12}
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
@@ -172,7 +172,7 @@ function Story(props) {
There are several different ways to specify props in JSX.
-### JavaScript Expressions
+### JavaScript Expressions as Props
You can pass any JavaScript expression as a prop, by surrounding it with `{}`. For example, in this JSX:
@@ -308,7 +308,7 @@ You can mix together different types of children, so you can use string literals
A React component can't return multiple React elements, but a single JSX expression can have multiple children, so if you want a component to render multiple things you can wrap it in a `div` like this.
-### JavaScript Expressions
+### JavaScript Expressions as Children
You can pass any JavaScript expression as children, by enclosing it within `{}`. For example, these expressions are equivalent:
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.
diff --git a/docs/docs/reference-react-component.md b/docs/docs/reference-react-component.md
index d8c2be7302fec..2c1b0770cb871 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.
@@ -136,7 +136,7 @@ If you "fork" props by using them for state, you might also want to implement [`
componentWillMount()
```
-`componentWillMount()` is invoked immediately before mounting occurs. It is called before `render()`, therefore setting state in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method.
+`componentWillMount()` is invoked immediately before mounting occurs. It is called before `render()`, therefore setting state synchronously in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method.
This is the only lifecycle hook called on server rendering. Generally, we recommend using the `constructor()` instead.
@@ -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).
* * *
diff --git a/docs/docs/typechecking-with-proptypes.md b/docs/docs/typechecking-with-proptypes.md
index 63c3241c2e1ce..85c128d3a909f 100644
--- a/docs/docs/typechecking-with-proptypes.md
+++ b/docs/docs/typechecking-with-proptypes.md
@@ -7,11 +7,13 @@ 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:
```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
};
```
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.
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/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 (
-
-
-
-
- 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.
+
+
+
+
+
+
+
);
- },
-});
+ }
+}
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/mocks/ReactElementTestChild.js b/mocks/ReactElementTestChild.js
index f2c94d5dd6885..2e9d076933047 100644
--- a/mocks/ReactElementTestChild.js
+++ b/mocks/ReactElementTestChild.js
@@ -13,10 +13,10 @@
var React = require('React');
-var Child = React.createClass({
- render: function() {
+class Child extends React.Component {
+ render() {
return React.createElement('div');
- },
-});
+ }
+}
module.exports = Child;
diff --git a/mocks/ReactMockedComponentTestComponent.js b/mocks/ReactMockedComponentTestComponent.js
index 903006487374f..285265df14876 100644
--- a/mocks/ReactMockedComponentTestComponent.js
+++ b/mocks/ReactMockedComponentTestComponent.js
@@ -13,23 +13,18 @@
var React = require('React');
-var ReactMockedComponentTestComponent = React.createClass({
- getDefaultProps: function() {
- return {bar: 'baz'};
- },
+class ReactMockedComponentTestComponent extends React.Component {
+ state = {foo: 'bar'};
- getInitialState: function() {
- return {foo: 'bar'};
- },
-
- hasCustomMethod: function() {
+ hasCustomMethod() {
return true;
- },
+ }
- render: function() {
+ render() {
return ;
- },
+ }
-});
+}
+ReactMockedComponentTestComponent.defaultProps = {bar: 'baz'};
module.exports = ReactMockedComponentTestComponent;
diff --git a/package.json b/package.json
index 9cc3af3f92680..7dba9499b1739 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.9",
"devDependencies": {
"aliasify": "^2.0.0",
"art": "^0.10.1",
@@ -43,6 +43,7 @@
"coffee-script": "^1.8.0",
"core-js": "^2.2.1",
"coveralls": "^2.11.6",
+ "create-react-class": "^15.5.2",
"del": "^2.0.2",
"derequire": "^2.0.3",
"escape-string-regexp": "^1.0.5",
@@ -72,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",
@@ -109,8 +111,8 @@
"jest": {
"modulePathIgnorePatterns": [
"/.module-cache/",
- "/react/build/",
- "/react/scripts/rollup/shims/"
+ "/build/",
+ "/scripts/rollup/shims/"
],
"rootDir": "",
"transform": {
diff --git a/packages/react-art/package.json b/packages/react-art/package.json
index b550b1e0fba68..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.7",
+ "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.7"
+ "react": "^16.0.0-alpha.9"
},
"files": [
"LICENSE",
diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json
index 831a2bed68e5e..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.7",
+ "version": "16.0.0-alpha.9",
"description": "React package for working with the DOM.",
"main": "index.js",
"repository": "facebook/react",
@@ -15,10 +15,11 @@
"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.7"
+ "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 0402ad8d006dd..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.7",
+ "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 eb2b8732f3e4c..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.7",
+ "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.7"
+ "react": "^16.0.0-alpha.9"
},
"files": [
"LICENSE",
diff --git a/packages/react/package.json b/packages/react/package.json
index 4ce3cc5b9ade9..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.7",
+ "version": "16.0.0-alpha.9",
"keywords": [
"react"
],
@@ -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 0c658781d6468..0cf8d024093b5 100644
--- a/scripts/fiber/tests-passing.txt
+++ b/scripts/fiber/tests-passing.txt
@@ -44,6 +44,9 @@ 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
@@ -89,23 +92,8 @@ 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
+src/isomorphic/classic/class/__tests__/create-react-class-integration-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
@@ -119,34 +107,13 @@ src/isomorphic/classic/class/__tests__/ReactClass-test.js
* 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
+* 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
-* 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 +132,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
@@ -314,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
@@ -495,8 +448,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 +669,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)
@@ -924,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
@@ -1299,7 +1250,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/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/build.js b/scripts/rollup/build.js
index 30d8d29e9a874..7f3055b099239 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(
@@ -242,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:
@@ -294,14 +305,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/bundles.js b/scripts/rollup/bundles.js
index a9010f0d0db35..cc33df8d123e8 100644
--- a/scripts/rollup/bundles.js
+++ b/scripts/rollup/bundles.js
@@ -44,8 +44,13 @@ const bundles = [
moduleName: 'React',
sourceMap: false,
},
- entry: 'src/umd/ReactUMDEntry.js',
- externals: [],
+ entry: 'src/isomorphic/React.js',
+ externals: [
+ 'create-react-class/factory',
+ 'prop-types',
+ 'prop-types/checkPropTypes',
+ 'prop-types/factory',
+ ],
fbEntry: 'src/fb/ReactFBEntry.js',
hasteName: 'React',
isRenderer: false,
@@ -53,9 +58,6 @@ const bundles = [
manglePropertiesOnProd: false,
name: 'react',
paths: [
- 'src/umd/ReactUMDEntry.js',
- 'src/umd/shims/**/*.js',
-
'src/isomorphic/**/*.js',
'src/addons/**/*.js',
@@ -76,8 +78,8 @@ const bundles = [
moduleName: 'ReactDOM',
sourceMap: false,
},
- entry: 'src/umd/ReactDOMUMDEntry.js',
- externals: [],
+ entry: 'src/renderers/dom/ReactDOM.js',
+ externals: ['prop-types', 'prop-types/checkPropTypes'],
fbEntry: 'src/fb/ReactDOMFBEntry.js',
hasteName: 'ReactDOMStack',
isRenderer: true,
@@ -85,12 +87,11 @@ 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.
+ 'src/isomorphic/classic/types/checkPropTypes.js',
'src/ReactVersion.js',
'src/shared/**/*.js',
],
@@ -106,8 +107,8 @@ const bundles = [
moduleName: 'ReactDOM',
sourceMap: false,
},
- entry: 'src/umd/ReactDOMUMDEntry.js',
- externals: [],
+ entry: 'src/renderers/dom/fiber/ReactDOMFiber.js',
+ externals: ['prop-types', 'prop-types/checkPropTypes'],
fbEntry: 'src/fb/ReactDOMFiberFBEntry.js',
hasteName: 'ReactDOMFiber',
isRenderer: true,
@@ -115,12 +116,11 @@ 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.
+ 'src/isomorphic/classic/types/checkPropTypes.js',
'src/ReactVersion.js',
'src/shared/**/*.js',
],
@@ -139,20 +139,19 @@ const bundles = [
moduleName: 'ReactDOMServer',
sourceMap: false,
},
- entry: 'src/umd/ReactDOMServerUMDEntry.js',
- externals: [],
- fbEntry: 'src/umd/ReactDOMServerUMDEntry.js',
+ entry: 'src/renderers/dom/ReactDOMServer.js',
+ externals: ['prop-types', 'prop-types/checkPropTypes'],
+ 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',
+ 'src/isomorphic/classic/types/checkPropTypes.js',
'src/ReactVersion.js',
'src/shared/**/*.js',
],
@@ -178,6 +177,8 @@ const bundles = [
'art/modes/current',
'art/modes/fast-noSideEffects',
'art/core/transform',
+ 'prop-types/checkPropTypes',
+ 'react-dom',
],
fbEntry: 'src/renderers/art/ReactARTStack.js',
hasteName: 'ReactARTStack',
@@ -186,11 +187,10 @@ 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',
+ 'src/isomorphic/classic/types/checkPropTypes.js',
'src/ReactVersion.js',
'src/shared/**/*.js',
],
@@ -213,6 +213,8 @@ const bundles = [
'art/modes/current',
'art/modes/fast-noSideEffects',
'art/core/transform',
+ 'prop-types/checkPropTypes',
+ 'react-dom',
],
fbEntry: 'src/renderers/art/ReactARTFiber.js',
hasteName: 'ReactARTFiber',
@@ -221,11 +223,10 @@ 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',
+ 'src/isomorphic/classic/types/checkPropTypes.js',
'src/ReactVersion.js',
'src/shared/**/*.js',
],
@@ -315,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,
@@ -327,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',
],
@@ -341,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,
@@ -353,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',
],
@@ -371,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,
@@ -380,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 2be3391469332..985fe8869087a 100644
--- a/scripts/rollup/modules.js
+++ b/scripts/rollup/modules.js
@@ -46,10 +46,18 @@ const fbjsModules = [
];
const devOnlyFilesToStubOut = [
+ "'ReactDebugCurrentFrame'",
"'ReactComponentTreeHook'",
- "'react/lib/ReactComponentTreeHook'",
- "'react-dom/lib/ReactPerf'",
- "'react-dom/lib/ReactTestUtils'",
+ "'ReactPerf'",
+ "'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
@@ -112,7 +120,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',
];
}
@@ -155,7 +162,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');
}
@@ -169,19 +176,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'
- ),
- };
-}
-
-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')}'`,
};
}
@@ -210,92 +204,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 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'
-);
-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,
- };
+ default:
+ return {};
}
}
@@ -320,11 +238,31 @@ 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(
- getReactCurrentOwnerModuleAlias(bundleType, isRenderer),
- getReactCheckPropTypesModuleAlias(bundleType, isRenderer),
- getReactComponentTreeHookModuleAlias(bundleType, isRenderer),
createModuleMap(
paths,
extractErrors && extractErrorCodes(errorCodeOpts),
@@ -339,9 +277,9 @@ function getAliases(paths, bundleType, isRenderer, extractErrors) {
function getDefaultReplaceModules(bundleType) {
return Object.assign(
{},
- replaceInternalModules(),
replaceFbjsModuleAliases(bundleType),
- replaceDevOnlyStubbedModules(bundleType)
+ replaceDevOnlyStubbedModules(bundleType),
+ replaceLegacyModuleAliases(bundleType)
);
}
@@ -353,17 +291,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..01bee146eedc6 100644
--- a/scripts/rollup/results.json
+++ b/scripts/rollup/results.json
@@ -2,116 +2,116 @@
"branch": "master",
"bundleSizes": {
"react.development.js (UMD_DEV)": {
- "size": 116402,
- "gzip": 29598
+ "size": 121454,
+ "gzip": 30515
},
"react.production.min.js (UMD_PROD)": {
- "size": 13719,
- "gzip": 5080
+ "size": 15685,
+ "gzip": 5765
},
"react-dom.development.js (UMD_DEV)": {
- "size": 564925,
- "gzip": 130471
+ "size": 583190,
+ "gzip": 134534
},
"react-dom.production.min.js (UMD_PROD)": {
- "size": 120123,
- "gzip": 37844
+ "size": 120740,
+ "gzip": 38094
},
"react-dom-server.development.js (UMD_DEV)": {
- "size": 477377,
- "gzip": 115561
+ "size": 495558,
+ "gzip": 119685
},
"react-dom-server.production.min.js (UMD_PROD)": {
- "size": 106349,
- "gzip": 32998
+ "size": 107033,
+ "gzip": 33273
},
"react-art.development.js (UMD_DEV)": {
- "size": 341151,
- "gzip": 76261
+ "size": 342608,
+ "gzip": 76782
},
"react-art.production.min.js (UMD_PROD)": {
- "size": 94939,
- "gzip": 28976
+ "size": 95013,
+ "gzip": 28991
},
"react.development.js (NODE_DEV)": {
- "size": 109416,
- "gzip": 27554
+ "size": 70266,
+ "gzip": 17594
},
"react.production.min.js (NODE_PROD)": {
- "size": 12615,
- "gzip": 4659
+ "size": 9226,
+ "gzip": 3628
},
"React-dev.js (FB_DEV)": {
- "size": 110901,
- "gzip": 28115
+ "size": 72123,
+ "gzip": 18231
},
"React-prod.js (FB_PROD)": {
- "size": 56205,
- "gzip": 14329
+ "size": 36643,
+ "gzip": 9256
},
"ReactDOMStack-dev.js (FB_DEV)": {
- "size": 523568,
- "gzip": 124900
+ "size": 522763,
+ "gzip": 124727
},
"ReactDOMStack-prod.js (FB_PROD)": {
- "size": 351707,
- "gzip": 84367
+ "size": 352776,
+ "gzip": 84675
},
"react-dom.development.js (NODE_DEV)": {
- "size": 543299,
- "gzip": 125435
+ "size": 542188,
+ "gzip": 125158
},
"react-dom.production.min.js (NODE_PROD)": {
- "size": 116802,
- "gzip": 36707
+ "size": 116925,
+ "gzip": 36732
},
"ReactDOMFiber-dev.js (FB_DEV)": {
- "size": 797779,
- "gzip": 184190
+ "size": 797235,
+ "gzip": 184122
},
"ReactDOMFiber-prod.js (FB_PROD)": {
- "size": 407360,
- "gzip": 93460
+ "size": 407613,
+ "gzip": 93586
},
"react-dom-server.development.js (NODE_DEV)": {
- "size": 446778,
- "gzip": 107862
+ "size": 445589,
+ "gzip": 107597
},
"react-dom-server.production.min.js (NODE_PROD)": {
- "size": 101204,
- "gzip": 31227
+ "size": 101411,
+ "gzip": 31292
},
"ReactDOMServerStack-dev.js (FB_DEV)": {
- "size": 445529,
- "gzip": 107719
+ "size": 444281,
+ "gzip": 107443
},
"ReactDOMServerStack-prod.js (FB_PROD)": {
- "size": 332974,
- "gzip": 80219
+ "size": 334166,
+ "gzip": 80444
},
"ReactARTStack-dev.js (FB_DEV)": {
- "size": 494340,
- "gzip": 118840
+ "size": 142986,
+ "gzip": 32714
},
"ReactARTStack-prod.js (FB_PROD)": {
- "size": 365115,
- "gzip": 87595
+ "size": 101143,
+ "gzip": 22993
},
"react-art.development.js (NODE_DEV)": {
- "size": 266386,
- "gzip": 57183
+ "size": 265052,
+ "gzip": 56927
},
"react-art.production.min.js (NODE_PROD)": {
- "size": 56517,
- "gzip": 17109
+ "size": 56628,
+ "gzip": 17152
},
"ReactARTFiber-dev.js (FB_DEV)": {
- "size": 265561,
- "gzip": 57011
+ "size": 264230,
+ "gzip": 56736
},
"ReactARTFiber-prod.js (FB_PROD)": {
- "size": 205194,
- "gzip": 43039
+ "size": 205336,
+ "gzip": 43154
},
"ReactNativeStack.js (RN)": {
"size": 233993,
@@ -122,20 +122,20 @@
"gzip": 84001
},
"ReactTestRendererFiber-dev.js (FB_DEV)": {
- "size": 263452,
- "gzip": 55974
+ "size": 262139,
+ "gzip": 55704
},
"ReactTestRendererStack-dev.js (FB_DEV)": {
- "size": 155222,
- "gzip": 35662
+ "size": 151521,
+ "gzip": 34765
},
"react-noop-renderer.development.js (NODE_DEV)": {
- "size": 255447,
- "gzip": 53933
+ "size": 254136,
+ "gzip": 53682
},
"react-test-renderer.development.js (NODE_DEV)": {
- "size": 264286,
- "gzip": 56152
+ "size": 262970,
+ "gzip": 55891
}
}
}
\ No newline at end of file
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/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/scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js b/scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js
similarity index 61%
rename from scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js
rename to scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js
index bcdc4d8787409..2174fb0166844 100644
--- a/scripts/rollup/shims/rollup/ReactComponentTreeHookRollupShim.js
+++ b/scripts/rollup/shims/rollup/ReactDebugCurrentFrameRollupShim.js
@@ -1,3 +1,3 @@
var ReactInternals = require('react').__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
-module.exports = ReactInternals.ReactComponentTreeHook;
+module.exports = ReactInternals.ReactDebugCurrentFrame;
diff --git a/src/ReactVersion.js b/src/ReactVersion.js
index 9df23ee824959..fd32524d89f46 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.9';
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 74add5c91bc8b..ac3fe41e622d9 100644
--- a/src/fb/ReactFBEntry.js
+++ b/src/fb/ReactFBEntry.js
@@ -11,26 +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,
- {
- // ReactComponentTreeHook should not be included in production.
- ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'),
- },
- );
-}
-
-module.exports = ReactFBEntry;
+module.exports = React;
diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js
index 4e03036be26e8..807a1c369f4f5 100644
--- a/src/isomorphic/React.js
+++ b/src/isomorphic/React.js
@@ -13,21 +13,22 @@
var ReactBaseClasses = require('ReactBaseClasses');
var ReactChildren = require('ReactChildren');
-var ReactClass = require('ReactClass');
var ReactDOMFactories = require('ReactDOMFactories');
var ReactElement = require('ReactElement');
var ReactPropTypes = require('ReactPropTypes');
var ReactVersion = require('ReactVersion');
var onlyChild = require('onlyChild');
-var warning = require('fbjs/lib/warning');
var checkPropTypes = require('checkPropTypes');
+var createReactClass = require('createClass');
var createElement = ReactElement.createElement;
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;
@@ -38,20 +39,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
@@ -70,12 +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,
- createClass: ReactClass.createClass,
createFactory: createFactory,
createMixin: createMixin,
@@ -84,6 +72,80 @@ 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'),
+ });
+
+ let warnedForCheckPropTypes = false;
+ let warnedForCreateMixin = false;
+ let warnedForCreateClass = false;
+ let warnedForPropTypes = 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;
+ };
+
+ // 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 drop-in replacement. ' +
+ '(https://fb.me/migrating-from-react-create-class)',
+ );
+ warnedForCreateClass = true;
+ 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;
+ },
+ });
+ }
+}
+
module.exports = React;
diff --git a/src/isomorphic/__tests__/React-test.js b/src/isomorphic/__tests__/React-test.js
index ec007f16a32b5..bd5d5bc1aaa4b 100644
--- a/src/isomorphic/__tests__/React-test.js
+++ b/src/isomorphic/__tests__/React-test.js
@@ -27,4 +27,48 @@ 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).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 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/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/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
index dfd0f21809005..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');
@@ -38,33 +40,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: PropTypes.string,
+ };
- getChildContext: function() {
+ class ComponentInFooBarContext extends React.Component {
+ getChildContext() {
return {
foo: 'abc',
bar: 123,
};
- },
+ }
- render: function() {
+ render() {
return ;
- },
- });
+ }
+ }
+ ComponentInFooBarContext.childContextTypes = {
+ foo: PropTypes.string,
+ bar: PropTypes.number,
+ };
var instance = ReactTestUtils.renderIntoDocument(
,
@@ -77,47 +77,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: PropTypes.string.isRequired,
+ bar: 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: PropTypes.string,
+ };
var container = document.createElement('div');
ReactDOM.render(, container);
@@ -130,37 +128,35 @@ 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: PropTypes.string.isRequired,
+ bar: 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: PropTypes.string,
+ };
var container = document.createElement('div');
ReactDOM.render(, container);
@@ -171,15 +167,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: PropTypes.string.isRequired,
+ };
ReactTestUtils.renderIntoDocument();
@@ -191,21 +186,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: PropTypes.string,
+ };
ReactTestUtils.renderIntoDocument(
,
@@ -214,21 +208,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: PropTypes.number,
+ };
ReactTestUtils.renderIntoDocument(
,
@@ -247,20 +240,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: PropTypes.string.isRequired,
+ bar: PropTypes.number,
+ };
ReactTestUtils.renderIntoDocument();
expectDev(console.error.calls.count()).toBe(1);
@@ -298,7 +290,7 @@ describe('ReactContextValidator', () => {
class ComponentA extends React.Component {
static childContextTypes = {
- foo: React.PropTypes.string.isRequired,
+ foo: PropTypes.string.isRequired,
};
render() {
return ;
@@ -306,7 +298,7 @@ describe('ReactContextValidator', () => {
}
class ComponentB extends React.Component {
static childContextTypes = {
- foo: React.PropTypes.string.isRequired,
+ foo: PropTypes.string.isRequired,
};
render() {
return ;
@@ -340,7 +332,7 @@ describe('ReactContextValidator', () => {
class ParentContextProvider extends React.Component {
static childContextTypes = {
- foo: React.PropTypes.number,
+ foo: PropTypes.number,
};
getChildContext() {
return {
@@ -354,7 +346,7 @@ describe('ReactContextValidator', () => {
class MiddleMissingContext extends React.Component {
static childContextTypes = {
- bar: React.PropTypes.string.isRequired,
+ bar: PropTypes.string.isRequired,
};
render() {
return ;
@@ -362,16 +354,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: PropTypes.string.isRequired,
+ foo: PropTypes.string.isRequired,
+ };
ReactTestUtils.renderIntoDocument();
expect(childContext.bar).toBeUndefined();
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__/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});
- });
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactClass-test.js b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js
similarity index 65%
rename from src/isomorphic/classic/class/__tests__/ReactClass-test.js
rename to src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js
index 4ab5ad7dac01e..55fb8c1ed8a49 100644
--- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js
+++ b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js
@@ -11,38 +11,37 @@
'use strict';
+var PropTypes;
var React;
var ReactDOM;
var ReactTestUtils;
+var createReactClass;
-describe('ReactClass-spec', () => {
+describe('create-react-class-integration', () => {
beforeEach(() => {
+ PropTypes = require('prop-types');
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('ReactTestUtils');
+ var createReactClassFactory = require('create-react-class/factory');
+ createReactClass = createReactClassFactory(
+ React.Component,
+ React.isValidElement,
+ require('ReactNoopUpdateQueue'),
+ );
});
it('should throw when `render` is not specified', () => {
expect(function() {
- React.createClass({});
+ createReactClass({});
}).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({
+ var TestComponent = createReactClass({
propTypes: {
value: propValidator,
},
@@ -57,7 +56,7 @@ describe('ReactClass-spec', () => {
it('should warn on invalid prop types', () => {
spyOn(console, 'error');
- React.createClass({
+ createReactClass({
displayName: 'Component',
propTypes: {
prop: null,
@@ -66,8 +65,8 @@ describe('ReactClass-spec', () => {
return {this.props.prop};
},
});
- expectDev(console.error.calls.count()).toBe(1);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ 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.',
);
@@ -75,7 +74,7 @@ describe('ReactClass-spec', () => {
it('should warn on invalid context types', () => {
spyOn(console, 'error');
- React.createClass({
+ createReactClass({
displayName: 'Component',
contextTypes: {
prop: null,
@@ -84,8 +83,8 @@ describe('ReactClass-spec', () => {
return {this.props.prop};
},
});
- expectDev(console.error.calls.count()).toBe(1);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ 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.',
);
@@ -93,7 +92,7 @@ describe('ReactClass-spec', () => {
it('should throw on invalid child context types', () => {
spyOn(console, 'error');
- React.createClass({
+ createReactClass({
displayName: 'Component',
childContextTypes: {
prop: null,
@@ -102,8 +101,8 @@ describe('ReactClass-spec', () => {
return {this.props.prop};
},
});
- expectDev(console.error.calls.count()).toBe(1);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ 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.',
);
@@ -112,7 +111,7 @@ describe('ReactClass-spec', () => {
it('should warn when mispelling shouldComponentUpdate', () => {
spyOn(console, 'error');
- React.createClass({
+ createReactClass({
componentShouldUpdate: function() {
return false;
},
@@ -120,14 +119,14 @@ describe('ReactClass-spec', () => {
return ;
},
});
- expectDev(console.error.calls.count()).toBe(1);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ expect(console.error.calls.count()).toBe(1);
+ expect(console.error.calls.argsFor(0)[0]).toBe(
'Warning: A component has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
);
- React.createClass({
+ createReactClass({
displayName: 'NamedComponent',
componentShouldUpdate: function() {
return false;
@@ -136,8 +135,8 @@ describe('ReactClass-spec', () => {
return ;
},
});
- expectDev(console.error.calls.count()).toBe(2);
- expectDev(console.error.calls.argsFor(1)[0]).toBe(
+ 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.',
@@ -146,7 +145,7 @@ describe('ReactClass-spec', () => {
it('should warn when mispelling componentWillReceiveProps', () => {
spyOn(console, 'error');
- React.createClass({
+ createReactClass({
componentWillRecieveProps: function() {
return false;
},
@@ -154,8 +153,8 @@ describe('ReactClass-spec', () => {
return ;
},
});
- expectDev(console.error.calls.count()).toBe(1);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ 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()?',
);
@@ -163,7 +162,7 @@ describe('ReactClass-spec', () => {
it('should throw if a reserved property is in statics', () => {
expect(function() {
- React.createClass({
+ createReactClass({
statics: {
getDefaultProps: function() {
return {
@@ -188,42 +187,42 @@ describe('ReactClass-spec', () => {
xit('should warn when using deprecated non-static spec keys', () => {
spyOn(console, 'error');
- React.createClass({
+ 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 ;
},
});
- expectDev(console.error.calls.count()).toBe(4);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ 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".',
);
- expectDev(console.error.calls.argsFor(1)[0]).toBe(
+ expect(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(
+ expect(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(
+ expect(console.error.calls.argsFor(3)[0]).toBe(
'createClass(...): `childContextTypes` is now a static property and ' +
'should be defined inside "statics".',
);
});
it('should support statics', () => {
- var Component = React.createClass({
+ var Component = createReactClass({
statics: {
abc: 'def',
def: 0,
@@ -253,7 +252,7 @@ describe('ReactClass-spec', () => {
});
it('should work with object getInitialState() return values', () => {
- var Component = React.createClass({
+ var Component = createReactClass({
getInitialState: function() {
return {
occupation: 'clown',
@@ -269,9 +268,9 @@ describe('ReactClass-spec', () => {
});
it('renders based on context getInitialState', () => {
- var Foo = React.createClass({
+ var Foo = createReactClass({
contextTypes: {
- className: React.PropTypes.string,
+ className: PropTypes.string,
},
getInitialState() {
return {className: this.context.className};
@@ -281,9 +280,9 @@ describe('ReactClass-spec', () => {
},
});
- var Outer = React.createClass({
+ var Outer = createReactClass({
childContextTypes: {
- className: React.PropTypes.string,
+ className: PropTypes.string,
},
getChildContext() {
return {className: 'foo'};
@@ -300,7 +299,7 @@ describe('ReactClass-spec', () => {
it('should throw with non-object getInitialState() return values', () => {
[['an array'], 'a string', 1234].forEach(function(state) {
- var Component = React.createClass({
+ var Component = createReactClass({
getInitialState: function() {
return state;
},
@@ -318,7 +317,7 @@ describe('ReactClass-spec', () => {
});
it('should work with a null getInitialState() return value', () => {
- var Component = React.createClass({
+ var Component = createReactClass({
getInitialState: function() {
return null;
},
@@ -332,17 +331,97 @@ describe('ReactClass-spec', () => {
it('should throw when using legacy factories', () => {
spyOn(console, 'error');
- var Component = React.createClass({
+ var Component = createReactClass({
render() {
return ;
},
});
expect(() => Component()).toThrow();
- expectDev(console.error.calls.count()).toBe(1);
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
+ 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 = createReactClass({
+ 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 = createReactClass({
+ 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/src/umd/ReactDOMServerUMDEntry.js b/src/isomorphic/classic/class/createClass.js
similarity index 50%
rename from src/umd/ReactDOMServerUMDEntry.js
rename to src/isomorphic/classic/class/createClass.js
index 7a55540e2b729..3791e5392dc0a 100644
--- a/src/umd/ReactDOMServerUMDEntry.js
+++ b/src/isomorphic/classic/class/createClass.js
@@ -6,11 +6,14 @@
* 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
+ * @providesModule createClass
*/
'use strict';
-var ReactDOMServer = require('ReactDOMServer');
+var {Component} = require('ReactBaseClasses');
+var {isValidElement} = require('ReactElement');
+var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
+var factory = require('create-react-class/factory');
-module.exports = ReactDOMServer;
+module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue);
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/element/__tests__/ReactElement-test.js b/src/isomorphic/classic/element/__tests__/ReactElement-test.js
index 27bd222be8ffd..30a74615feb3c 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
- );
- },
- });
- 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
');
});
- 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('
;
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/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/dom/shared/findDOMNode.js b/src/renderers/dom/shared/findDOMNode.js
index ea1ef8d0f423d..1374e320a6b31 100644
--- a/src/renderers/dom/shared/findDOMNode.js
+++ b/src/renderers/dom/shared/findDOMNode.js
@@ -10,8 +10,9 @@
* @flow
*/
-var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var ReactInstanceMap = require('ReactInstanceMap');
+var {ELEMENT_NODE} = require('HTMLNodeType');
+var {ReactCurrentOwner} = require('ReactGlobalSharedState');
var getComponentName = require('getComponentName');
var invariant = require('fbjs/lib/invariant');
@@ -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/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/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/ReactControlledValuePropTypes.js b/src/renderers/dom/shared/utils/ReactControlledValuePropTypes.js
index e0cdedf22f5c7..48c37b67a3039 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,23 +57,17 @@ var propTypes = {
'set either `onChange` or `readOnly`.',
);
},
- onChange: React.PropTypes.func,
+ onChange: PropTypes.func,
};
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/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/shared/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js
index 62df49a453262..ac76902e0cf15 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();
@@ -638,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', () => {
@@ -738,11 +749,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 +766,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 +786,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 +801,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 +816,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 +833,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 +850,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 +867,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 +882,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 +897,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 +912,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 +927,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 +942,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 +957,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 +972,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 +1028,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 **)',
);
});
@@ -1119,22 +1146,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() {
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