diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..16c83a61d69 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,22 @@ +version: 2 +jobs: + build: + docker: + - image: circleci/node:latest + steps: + - checkout + - restore_cache: + keys: + - dependencies-{{ checksum "package.json" }} + # fallback to using the latest cache if no exact match is found + - dependencies- + - run: + name: Install + command: yarn install + - save_cache: + paths: + - node_modules + key: dependencies-{{ checksum "package.json" }} + - run: + name: Check Prettier, ESLint, Flow + command: yarn ci-check diff --git a/.eslintignore b/.eslintignore index ff8a5577f95..9425417154d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,4 +4,7 @@ node_modules/* content/* # Ignore built files -public/* \ No newline at end of file +public/* + +# Ignore examples +examples/* \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 78354d1e389..a51454ef284 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,18 @@ { + "extends": [ + "fbjs" + ], "plugins": [ "prettier", "react" ], "parser": "babel-eslint", -} \ No newline at end of file + "rules": { + "relay/graphql-naming": 0, + "max-len": 0 + }, + "env": { + "node": true, + "browser": true + } +} diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..d3c569401c7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ + + + diff --git a/.gitignore b/.gitignore index 237a1c464a8..dbe72d17694 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .cache .DS_STORE +.idea node_modules -public \ No newline at end of file +public diff --git a/.prettierrc.examples b/.prettierrc.examples new file mode 100644 index 00000000000..bd17fb7e3c8 --- /dev/null +++ b/.prettierrc.examples @@ -0,0 +1,8 @@ +{ + "bracketSpacing": false, + "jsxBracketSameLine": true, + "parser": "flow", + "printWidth": 60, + "singleQuote": true, + "trailingComma": "es5" +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..a39bdf94532 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,139 @@ +# Contributing + +Thank you for your interest in contributing to the React Docs! + +## Code of Conduct + +Facebook has adopted a Code of Conduct that we expect project +participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) +so that you can understand what actions will and will not be tolerated. + +## Guidelines for Text + +**Different sections intentionally have different styles.** + +The documentation is divided into sections to cater to different learning styles and use cases. When editing an article, try to match the surrounding text in tone and style. When creating a new article, try to match the tone of the other articles in the same section. Learn about the motivation behind each section below. + +**[Tutorial](https://reactjs.org/tutorial/tutorial.html)** is relatively informal, and is designed for people who prefer a hands-on approach to learning, and can tolerate skipping theory in favor of practice. Its goal is to give the reader a feel for a typical React workflow rather than to explain fundamentals in detail. Here we focus on *what* to do and spend less time on *how* or *why* we did it. It is extremely important to do a lot of hand-holding and unambiguously describe every single change. It should be possible for a beginner to mechanically follow every instruction, and still get to a working tic-tac-toe game. + +**[Quick Start](https://reactjs.org/docs/hello-world.html)** is designed to introduce fundamental concepts in a step-by-step way. Each individual article in Quick Start builds on the knowledge from the previous ones, so make sure not to add any "cyclical dependencies" between them. It is important that the reader can start with the first article and work their way to the last Quick Start article without ever having to "look ahead" for a definition. This explains some ordering choices (e.g. that state is explained before events, or that "thinking in React" doesn't use refs). Quick Start also serves as a reference manual for React concepts, so it is important to be very strict about their definitions and relationships between them. This is, for example, why we introduce elements before components. Resist adding too much detail to Quick Start articles. They intentionally don't cover all corner cases, and focus on establishing firm foundations. + +**[Advanced Guides](https://reactjs.org/docs/jsx-in-depth.html)** are deep dives into topics that aren't essential for a beginner developer but that everyone bumps into sooner or later. They don't have a specific order, and target more experienced developers. If you have a set of recipes fitting a particular use case, and those recipes aren't opinionated (most React users would agree on them), this is the place to add them. + +**[Reference](https://reactjs.org/docs/react-api.html)** is organized by APIs rather than concepts. It is intended to be exhaustive. Any corner cases or recommendations that were skipped for brevity in Quick Start or Advanced Guides should be mentioned in the reference documentation for the corresponding APIs. + +**[Contributing](https://reactjs.org/docs/how-to-contribute.html)** should stay up-to-date and be friendly to relatively experienced developers. + +**[FAQ](https://reactjs.org/docs/faq-ajax.html)** has a more conversational tone than the other sections. Here, it's fine to include some content that's not primarily concerned with React, as long as React users are overwhelmingly interested in it (e.g. recommendations on directory structure). It's also okay to show more than a single way to do something in the FAQ, and briefly discuss the tradeoffs. The FAQ prioritizes unblocking people with a working solution over explaining concepts in detail, and can be more opinionated than the rest of the docs, even providing popular library recommendations. + +**Try to follow your own instructions.** + +When writing step-by-step instructions (e.g. how to install something), try to forget everything you know about the topic, and actually follow the instructions you wrote, a single step at time. Often you will discover that there is implicit knowledge that you forgot to mention, or that there are missing or out-of-order steps in the instructions. Bonus points for getting *somebody else* to follow the steps and watching what they struggle with. Often it would be something very simple that you have not anticipated. + +## Guidelines for Code Examples + +### Syntax + +#### Prefer JSX to `createElement`. + +Ignore this if you're specifically describing `createElement`. + +#### Use `const` where possible, otherwise `let`. Don't use `var`. + +Ignore this if you're specifically writing about ES5. + +#### Don't use ES6 features when equivalent ES5 features have no downsides. + +Remember that ES6 is still new to a lot of people. While we use it in many places (`const` / `let`, classes, arrow functions), if the equivalent ES5 code is just as straightforward and readable, consider using it. + +In particular, you should prefer named `function` declarations over `const myFunction = () => ...` arrows for top-level functions. However, you *should* use arrow functions where they provide a tangible improvement (such as preserving `this` context inside a component). Consider both sides of the tradeoff when deciding whether to use a new feature. + +#### Don't use features that aren't standardized yet. + +For example, **don't** write this: + +```js +class MyComponent extends React.Component { + state = {value: ''}; + handleChange = (e) => { + this.setState({value: e.target.value}); + }; +} +``` + +Instead, **do** write this: + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props) + this.handleChange = this.handleChange.bind(this); + this.state = {value: ''}; + } + handleChange(e) { + this.setState({value: e.target.value}); + } +} +``` + +Ignore this rule if you're specifically describing an experimental proposal. Make sure to mention its experimental nature in the code and in the surrounding text. + +### Style + +- Use semicolons. +- No space between function names and parens (`method() {}` not `method () {}`). +- When in doubt, use the default style favored by [Prettier](https://prettier.io/playground/). + +### Highlighting + +Use `js` as the highlighting language in Markdown code blocks: + +```` +```js +// code +``` +```` + +Sometimes you'll see blocks with numbers. +They tell the website to highlight specific lines. + +You can highlight a single line: + +```` +```js{2} +function hello() { + // this line will get highlighted +} +``` +```` + +A range of lines: + +```` +```js{2-4} +function hello() { + // these lines + // will get + // highlighted +} +``` +```` + +Or even multiple ranges: + +```` +```js{2-4,6} +function hello() { + // these lines + // will get + // highlighted + console.log('hello'); + // also this one + console.log('there'); +} +``` +```` + +Be mindful that if you move some code in an example with highlighting, you also need to update the highlighting. + +Don't be afraid to often use highlighting! It is very valuable when you need to focus the reader's attention on a particular detail that's easy to miss. diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 5930f2b8d81..00000000000 --- a/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2013-present, Facebook, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 45a212183b3..74c6e5a577d 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,13 @@ This repo contains the source code and documentation powering [reactjs.org](http 1. Git 1. Node: install version 8.4 or greater 1. Yarn: See [Yarn website for installation instructions](https://yarnpkg.com/lang/en/docs/install/) -1. A clone of the [reactjs.org repo](https://github.com/reactjs/reactjs.org) on your local machine 1. A fork of the repo (for any contributions) +1. A clone of the [reactjs.org repo](https://github.com/reactjs/reactjs.org) on your local machine ### Installation 1. `cd reactjs.org` to go into the project root -1. `yarn` to install the website's NPM dependencies +1. `yarn` to install the website's npm dependencies ### Running locally @@ -24,6 +24,10 @@ This repo contains the source code and documentation powering [reactjs.org](http ## Contributing +### Guidelines + +The documentation is divided into several sections with a different tone and purpose. If you plan to write more than a few sentences, you might find it helpful to get familiar with the [contributing guidelines](https://github.com/reactjs/reactjs.org/blob/master/CONTRIBUTING.md#guidelines-for-text) for the appropriate sections. + ### Create a branch 1. `git checkout master` from any folder in your local `reactjs.org` repository @@ -41,7 +45,7 @@ This repo contains the source code and documentation powering [reactjs.org](http ### Test the change 1. If possible, test any visual changes in all latest versions of common browsers, on both desktop and mobile. -1. Run `yarn check-all` from the project root. (This will run Prettier, ESlint, and Flow.) +1. Run `yarn check-all` from the project root. (This will run Prettier, ESLint, and Flow.) ### Push it @@ -49,7 +53,13 @@ This repo contains the source code and documentation powering [reactjs.org](http 1. `git push my-fork-name the-name-of-my-branch` 1. Go to the [reactjs.org repo](https://github.com/reactjs/reactjs.org) and you should see recently pushed branches. 1. Follow GitHub's instructions. -1. If possible include screenshots of visual changes. A Netlify build will also be automatically created once you make your PR so other people can see your change. +1. If possible, include screenshots of visual changes. A Netlify build will also be automatically created once you make your PR so other people can see your change. + +## Translation + +If you are interesting in translating `reactjs.org`, please join the Crowdin. + +* [Crowdin - React](https://crowdin.com/project/react) ## Troubleshooting diff --git a/content/authors.yml b/content/authors.yml index e9105367c47..b5817e4781c 100644 --- a/content/authors.yml +++ b/content/authors.yml @@ -7,9 +7,15 @@ acdlite: benigeri: name: Paul Benigeri url: https://github.com/benigeri +bvaughn: + name: Brian Vaughn + url: https://github.com/bvaughn chenglou: name: Cheng Lou url: https://twitter.com/_chenglou +clemmy: + name: Clement Hoang + url: https://twitter.com/c8hoang Daniel15: name: Daniel Lo Nigro url: http://dan.cx/ @@ -63,7 +69,7 @@ sebmarkbage: url: https://twitter.com/sebmarkbage sophiebits: name: Sophie Alpert - url: https://sophiealpert.com + url: https://sophiebits.com/ steveluscher: name: Steven Luscher url: https://twitter.com/steveluscher diff --git a/content/blog/2013-06-05-why-react.md b/content/blog/2013-06-05-why-react.md index 79e5af0baaf..30d54b24c84 100644 --- a/content/blog/2013-06-05-why-react.md +++ b/content/blog/2013-06-05-why-react.md @@ -80,7 +80,7 @@ some pretty cool things with it: (including IE8) and automatically use [event delegation](http://davidwalsh.name/event-delegate). -Head on over to https://reactjs.org to check out what we have +Head on over to [https://reactjs.org](https://reactjs.org) to check out what we have built. Our documentation is geared towards building apps with the framework, but if you are interested in the nuts and bolts [get in touch](/support.html) with us! diff --git a/content/blog/2014-10-16-react-v0.12-rc1.md b/content/blog/2014-10-16-react-v0.12-rc1.md index 2bb088f4f6a..cff02743014 100644 --- a/content/blog/2014-10-16-react-v0.12-rc1.md +++ b/content/blog/2014-10-16-react-v0.12-rc1.md @@ -22,7 +22,7 @@ We've also published version `0.12.0-rc1` of the `react` and `react-tools` packa ## React Elements -The biggest conceptual change we made in v0.12 is the move to React Elements. [We talked about this topic in depth earlier this week](/blog/2014/10/14/introducting-react-elements.html). If you haven't already, you should read up on the exciting changes in there! +The biggest conceptual change we made in v0.12 is the move to React Elements. [We talked about this topic in depth earlier this week](/blog/2014/10/14/introducing-react-elements.html). If you haven't already, you should read up on the exciting changes in there! ## JSX Changes diff --git a/content/blog/2015-03-30-community-roundup-26.md b/content/blog/2015-03-30-community-roundup-26.md index d45b3051f4a..1ad461ad658 100644 --- a/content/blog/2015-03-30-community-roundup-26.md +++ b/content/blog/2015-03-30-community-roundup-26.md @@ -67,7 +67,7 @@ Jay Garcia spent a lot of time during the beta working on a NES music player wit ## React Native with Babel and webpack -React Native ships with a custom packager and custom ES6 transforms instead of using what the open source community settled on such as webpack and Babel. The main reason for this is performance – we couldn't get those tools to have sub-second reload time on a large codebase. +React Native ships with a custom packager and custom ES6 transforms instead of using what the open source community settled on such as [webpack](https://webpack.js.org/) and [Babel](https://babeljs.io/). The main reason for this is performance – we couldn't get those tools to have sub-second reload time on a large codebase. Roman Liutikov found a way to [use webpack and Babel to run on React Native](https://github.com/roman01la/react-native-babel)! In the future, we want to work with those projects to provide cleaner extension mechanisms. diff --git a/content/blog/2015-07-03-react-v0.14-beta-1.md b/content/blog/2015-07-03-react-v0.14-beta-1.md index 57db47aa5b3..4f1450556ac 100644 --- a/content/blog/2015-07-03-react-v0.14-beta-1.md +++ b/content/blog/2015-07-03-react-v0.14-beta-1.md @@ -7,7 +7,7 @@ This week, many people in the React community are at [ReactEurope](https://www.r With React 0.14, we're continuing to let React mature and to make minor changes as the APIs continue to settle down. I'll talk only about the two largest changes in this blog post; when we publish the final release we'll be sure to update all of our documentation and include a full changelog. -You can install the new beta with `npm install react@0.14.0-beta1` and `npm install react-dom@0.14.0-beta1`. As mentioned in [Deprecating react-tools](https://reactjs.org/blog/2015/06/12/deprecating-jstransform-and-react-tools.html), we're no longer updating the react-tools package so this release doesn't include a new version of it. Please try the new version out and let us know what you think, and please do file issues on our GitHub repo if you run into any problems. +You can install the new beta with `npm install react@0.14.0-beta1` and `npm install react-dom@0.14.0-beta1`. As mentioned in [Deprecating react-tools](/blog/2015/06/12/deprecating-jstransform-and-react-tools.html), we're no longer updating the react-tools package so this release doesn't include a new version of it. Please try the new version out and let us know what you think, and please do file issues on our GitHub repo if you run into any problems. ## Two Packages diff --git a/content/blog/2015-12-16-ismounted-antipattern.md b/content/blog/2015-12-16-ismounted-antipattern.md index c49e2cf1bb2..3fc654621b0 100644 --- a/content/blog/2015-12-16-ismounted-antipattern.md +++ b/content/blog/2015-12-16-ismounted-antipattern.md @@ -43,7 +43,7 @@ If you use ES6 promises, you may need to wrap your promise in order to make it c ```js const cancelablePromise = makeCancelable( - new Promise(r => component.setState({...}})) + new Promise(r => component.setState({...})) ); cancelablePromise diff --git a/content/blog/2017-04-07-react-v15.5.0.md b/content/blog/2017-04-07-react-v15.5.0.md index eea84664635..a0654165620 100644 --- a/content/blog/2017-04-07-react-v15.5.0.md +++ b/content/blog/2017-04-07-react-v15.5.0.md @@ -63,7 +63,7 @@ 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). +You may also consider using [Flow](https://flow.org/) to statically type check your JavaScript code, including [React components](https://flow.org/en/docs/react/components/). ### Migrating from React.createClass @@ -113,8 +113,8 @@ We're discontinuing active maintenance of React Addons packages. In truth, most - **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`](/docs/react-api.html#react.purecomponent) instead. -- **react-addons-shallow-compare** - Use [`React.PureComponent`](/docs/react-api.html#react.purecomponent) instead. +- **react-addons-pure-render-mixin** - Use [`React.PureComponent`](/docs/react-api.html#reactpurecomponent) instead. +- **react-addons-shallow-compare** - Use [`React.PureComponent`](/docs/react-api.html#reactpurecomponent) 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. diff --git a/content/blog/2017-09-08-dom-attributes-in-react-16.md b/content/blog/2017-09-08-dom-attributes-in-react-16.md index a8ded510565..b8953997cfd 100644 --- a/content/blog/2017-09-08-dom-attributes-in-react-16.md +++ b/content/blog/2017-09-08-dom-attributes-in-react-16.md @@ -163,7 +163,7 @@ Below is a detailed list of them. ``` React 15: Converts `NaN`s to strings and passes them through. - React 16: Warns and ignores them. + React 16: Converts `NaN`s to strings and passes them through with a warning. While testing this release, we have also [created an automatically generated table](https://github.com/facebook/react/blob/master/fixtures/attribute-behavior/AttributeTableSnapshot.md) for all known attributes to track potential regressions. diff --git a/content/blog/2017-09-26-react-v16.0.md b/content/blog/2017-09-26-react-v16.0.md index 9636e8f38a0..1e3a41942a8 100644 --- a/content/blog/2017-09-26-react-v16.0.md +++ b/content/blog/2017-09-26-react-v16.0.md @@ -21,7 +21,7 @@ render() { } ``` -In the future, we'll likely add a special fragment syntax to JSX that doesn't require keys. +[Starting with React 16.2.0](/blog/2017/11/28/react-v16.2.0-fragment-support.html), we are adding support for a special fragment syntax to JSX that doesn't require keys. We've added support for returning strings, too: @@ -65,13 +65,13 @@ React 16 includes a completely rewritten server renderer. It's really fast. It s Core team member Sasha Aickin wrote a [great article describing React 16's SSR improvements](https://medium.com/@aickin/whats-new-with-server-side-rendering-in-react-16-9b0d78585d67). According to Sasha's synthetic benchmarks, server rendering in React 16 is roughly **three times faster** than React 15. "When comparing against React 15 with `process.env` compiled out, there’s about a 2.4x improvement in Node 4, about a 3x performance improvement in Node 6, and a full 3.8x improvement in the new Node 8.4 release. And if you compare against React 15 without compilation, React 16 has a full order of magnitude gain in SSR in the latest version of Node!" (As Sasha points out, please be aware that these numbers are based on synthetic benchmarks and may not reflect real-world performance.) -In addition, React 16 is better at hydrating server-rendered HTML once it reaches the client. It no longer requires the initial render to exactly match the result from the server. Instead, it will attempt to reuse as much of the existing DOM as possible. No more checksums! In general, we don't recommend that you render different content on the client versus the server, but it can be useful in some cases (e.g. timestamps). +In addition, React 16 is better at hydrating server-rendered HTML once it reaches the client. It no longer requires the initial render to exactly match the result from the server. Instead, it will attempt to reuse as much of the existing DOM as possible. No more checksums! In general, we don't recommend that you render different content on the client versus the server, but it can be useful in some cases (e.g. timestamps). **However, it's dangerous to have missing nodes on the server render as this might cause sibling nodes to be created with incorrect attributes.** See the [documentation for `ReactDOMServer`](/docs/react-dom-server.html) for more details. ### Support for custom DOM attributes -Instead of ignoring unrecognized HTML and SVG attributes, React will now [pass them through to the DOM](https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html). This has the added benefit of allowing us to get rid of most of React's attribute whitelist, resulting in reduced file sizes. +Instead of ignoring unrecognized HTML and SVG attributes, React will now [pass them through to the DOM](/blog/2017/09/08/dom-attributes-in-react-16.html). This has the added benefit of allowing us to get rid of most of React's attribute whitelist, resulting in reduced file sizes. ### Reduced file size @@ -134,6 +134,9 @@ Refer to the documentation for [detailed installation instructions](/docs/instal Although React 16 includes significant internal changes, in terms of upgrading, you can think of this like any other major React release. We've been serving React 16 to Facebook and Messenger.com users since earlier this year, and we released several beta and release candidate versions to flush out additional issues. With minor exceptions, **if your app runs in 15.6 without any warnings, it should work in 16.** +For deprecations listed in [packaging](#packaging) below, codemods are provided to automatically transform your deprecated code. +See the [15.5.0](/blog/2017/04/07/react-v15.5.0.html) blog post for more information, or browse the codemods in the [react-codemod](https://github.com/reactjs/react-codemod) project. + ### New deprecations Hydrating a server-rendered container now has an explicit API. If you're reviving server-rendered HTML, use [`ReactDOM.hydrate`](/docs/react-dom.html#hydrate) instead of `ReactDOM.render`. Keep using `ReactDOM.render` if you're just doing client-side rendering. @@ -151,7 +154,7 @@ Refer to the previous announcement for [suggestions on how to migrate](/blog/201 React 16 includes a number of small breaking changes. These only affect uncommon use cases and we don't expect them to break most apps. * React 15 had limited, undocumented support for error boundaries using `unstable_handleError`. This method has been renamed to `componentDidCatch`. You can use a codemod to [automatically migrate to the new API](https://github.com/reactjs/react-codemod#error-boundaries). -* `ReactDOM.render` and `ReactDOM.unstable_renderIntoContainer` now return null if called from inside a lifecycle method. To work around this, you can use [portals](https://github.com/facebook/react/issues/10309#issuecomment-318433235) or [refs](https://github.com/facebook/react/issues/10309#issuecomment-318434635). +* `ReactDOM.render` and `ReactDOM.unstable_renderSubtreeIntoContainer` now return null if called from inside a lifecycle method. To work around this, you can use [portals](https://github.com/facebook/react/issues/10309#issuecomment-318433235) or [refs](https://github.com/facebook/react/issues/10309#issuecomment-318434635). * `setState`: * Calling `setState` with null no longer triggers an update. This allows you to decide in an updater function if you want to re-render. * Calling `setState` directly in render always causes an update. This was not previously the case. Regardless, you should not be calling setState from render. @@ -168,7 +171,7 @@ React 16 includes a number of small breaking changes. These only affect uncommon * There is no `react/lib/*` and `react-dom/lib/*` anymore. Even in CommonJS environments, React and ReactDOM are precompiled to single files (“flat bundles”). If you previously relied on undocumented React internals, and they don’t work anymore, let us know about your specific case in a new issue, and we’ll try to figure out a migration strategy for you. * There is no `react-with-addons.js` build anymore. All compatible addons are published separately on npm, and have single-file browser versions if you need them. -* The deprecations introduced in 15.x have been removed from the core package. `React.createClass` is now available as `create-react-class`, `React.PropTypes` as `prop-types`, `React.DOM` as `react-dom-factories`, `react-addons-test-utils` as `react-dom/test-utils`, and shallow renderer as `react-test-renderer/shallow`. See [15.5.0](https://reactjs.org/blog/2017/04/07/react-v15.5.0.html) and [15.6.0](https://reactjs.org/blog/2017/06/13/react-v15.6.0.html) blog posts for instructions on migrating code and automated codemods. +* The deprecations introduced in 15.x have been removed from the core package. `React.createClass` is now available as `create-react-class`, `React.PropTypes` as `prop-types`, `React.DOM` as `react-dom-factories`, `react-addons-test-utils` as `react-dom/test-utils`, and shallow renderer as `react-test-renderer/shallow`. See [15.5.0](/blog/2017/04/07/react-v15.5.0.html) and [15.6.0](/blog/2017/06/13/react-v15.6.0.html) blog posts for instructions on migrating code and automated codemods. * The names and paths to the single-file browser builds have changed to emphasize the difference between development and production builds. For example: * `react/dist/react.js` → `react/umd/react.development.js` * `react/dist/react.min.js` → `react/umd/react.production.min.js` @@ -194,12 +197,11 @@ ReactDOM.render( ); ``` -React also depends on `requestAnimationFrame` (even in test environments). A simple shim for test environments would be: +React also depends on `requestAnimationFrame` (even in test environments). +You can use the [raf](https://www.npmjs.com/package/raf) package to shim `requestAnimationFrame`: ```js -global.requestAnimationFrame = function(callback) { - setTimeout(callback, 0); -}; +import 'raf/polyfill'; ``` ## Acknowledgments diff --git a/content/blog/2017-11-28-react-v16.2.0-fragment-support.md b/content/blog/2017-11-28-react-v16.2.0-fragment-support.md new file mode 100644 index 00000000000..a29368d9061 --- /dev/null +++ b/content/blog/2017-11-28-react-v16.2.0-fragment-support.md @@ -0,0 +1,327 @@ +--- +title: "React v16.2.0: Improved Support for Fragments" +author: [clemmy] +--- + +React 16.2 is now available! The biggest addition is improved support for returning multiple children from a component's render method. We call this feature *fragments*: + +Fragments look like empty JSX tags. They let you group a list of children without adding extra nodes to the DOM: + +```js +render() { + return ( + <> + + + + + ); +} +``` + +This exciting new feature is made possible by additions to both React and JSX. + +## What Are Fragments? + +A common pattern is for a component to return a list of children. Take this example HTML: + +```html +Some text. +

A heading

+More text. +

Another heading

+Even more text. +``` + +Prior to version 16, the only way to achieve this in React was by wrapping the children in an extra element, usually a `div` or `span`: + +```js +render() { + return ( + // Extraneous div element :( +
+ Some text. +

A heading

+ More text. +

Another heading

+ Even more text. +
+ ); +} +``` + +To address this limitation, React 16.0 added support for [returning an array of elements from a component's `render` method](https://reactjs.org/blog/2017/09/26/react-v16.0.html#new-render-return-types-fragments-and-strings). Instead of wrapping the children in a DOM element, you can put them into an array: + +```jsx +render() { + return [ + "Some text.", +

A heading

, + "More text.", +

Another heading

, + "Even more text." + ]; +} +``` + +However, this has some confusing differences from normal JSX: + +- Children in an array must be separated by commas. +- Children in an array must have a key to prevent React's [key warning](https://reactjs.org/docs/lists-and-keys.html#keys). +- Strings must be wrapped in quotes. + +To provide a more consistent authoring experience for fragments, React now provides a first-class `Fragment` component that can be used in place of arrays. + +```jsx{3,9} +render() { + return ( + + Some text. +

A heading

+ More text. +

Another heading

+ Even more text. +
+ ); +} +``` + +You can use `` the same way you'd use any other element, without changing the way you write JSX. No commas, no keys, no quotes. + +The Fragment component is available on the main React object: + +```js +const Fragment = React.Fragment; + + + + + + + +// This also works + + + + + +``` + +## JSX Fragment Syntax + +Fragments are a common pattern in our codebases at Facebook. We anticipate they'll be widely adopted by other teams, too. To make the authoring experience as convenient as possible, we're adding syntactical support for fragments to JSX: + +```jsx{3,9} +render() { + return ( + <> + Some text. +

A heading

+ More text. +

Another heading

+ Even more text. + + ); +} +``` + +In React, this desugars to a `` element, as in the example from the previous section. (Non-React frameworks that use JSX may compile to something different.) + +Fragment syntax in JSX was inspired by prior art such as the `XMLList() <>` constructor in [E4X](https://developer.mozilla.org/en-US/docs/Archive/Web/E4X/E4X_for_templating). Using a pair of empty tags is meant to represent the idea it won't add an actual element to the DOM. + +### Keyed Fragments + +Note that the `<>` syntax does not accept attributes, including keys. + +If you need a keyed fragment, you can use `` directly. A use case for this is mapping a collection to an array of fragments -- for example, to create a description list: + +```jsx +function Glossary(props) { + return ( +
+ {props.items.map(item => ( + // Without the `key`, React will fire a key warning + +
{item.term}
+
{item.description}
+
+ ))} +
+ ); +} +``` + +`key` is the only attribute that can be passed to `Fragment`. In the future, we may add support for additional attributes, such as event handlers. + +### Live Demo + +You can experiment with JSX fragment syntax with this [CodePen](https://codepen.io/reactjs/pen/VrEbjE?editors=1000). + +## Support for Fragment Syntax + +Support for fragment syntax in JSX will vary depending on the tools you use to build your app. Please be patient as the JSX community works to adopt the new syntax. We've been working closely with maintainers of the most popular projects: + +### Create React App + +Experimental support for fragment syntax will be added to Create React App within the next few days. A stable release may take a bit longer as we await adoption by upstream projects. + +### Babel + +Support for JSX fragments is available in [Babel v7.0.0-beta.31](https://github.com/babel/babel/releases/tag/v7.0.0-beta.31) and above! If you are already on Babel 7, simply update to the latest Babel and plugin transform: + +```bash +# for yarn users +yarn upgrade @babel/core @babel/plugin-transform-react-jsx +# for npm users +npm update @babel/core @babel/plugin-transform-react-jsx +``` + +Or if you are using the [react preset](https://www.npmjs.com/package/@babel/preset-react): + +```bash +# for yarn users +yarn upgrade @babel/core @babel/preset-react +# for npm users +npm update @babel/core @babel/preset-react +``` + +Note that Babel 7 is technically still in beta, but a [stable release is coming soon](https://babeljs.io/blog/2017/09/12/planning-for-7.0). + +Unfortunately, support for Babel 6.x is not available, and there are currently no plans to backport. + +#### Babel with Webpack (babel-loader) + +If you are using Babel with [Webpack](https://webpack.js.org/), no additional steps are needed because [babel-loader](https://github.com/babel/babel-loader) will use your peer-installed version of Babel. + +#### Babel with Other Frameworks + +If you use JSX with a non-React framework like Inferno or Preact, there is a [pragma option available in babel-plugin-transform-react-jsx](https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx#pragmafrag) that configures the Babel compiler to de-sugar the `<>` syntax to a custom identifier. + +### TypeScript + +TypeScript has full support for fragment syntax! Please upgrade to [version 2.6.2](https://github.com/Microsoft/TypeScript/releases/tag/v2.6.2). (Note that this is important even if you are already on version 2.6.1, since support was added as patch release in 2.6.2.) + +Upgrade to the latest TypeScript with the command: + +```bash +# for yarn users +yarn upgrade typescript +# for npm users +npm update typescript +``` + +### Flow + +[Flow](https://flow.org/) support for JSX fragments is available starting in [version 0.59](https://github.com/facebook/flow/releases/tag/v0.59.0)! Simply run + +```bash +# for yarn users +yarn upgrade flow-bin +# for npm users +npm update flow-bin +``` + +to update Flow to the latest version. + +### Prettier + +[Prettier](https://github.com/prettier/prettier) added support for fragments in their [1.9 release](https://prettier.io/blog/2017/12/05/1.9.0.html#jsx-fragment-syntax-3237-https-githubcom-prettier-prettier-pull-3237-by-duailibe-https-githubcom-duailibe). + +### ESLint + +JSX Fragments are supported by [ESLint](https://eslint.org/) 3.x when it is used together with [babel-eslint](https://github.com/babel/babel-eslint): + +```bash +# for yarn users +yarn add eslint@3.x babel-eslint@7 +# for npm users +npm install eslint@3.x babel-eslint@7 +``` + +or if you already have it, then upgrade: + +```bash +# for yarn users +yarn upgrade eslint@3.x babel-eslint@7 +# for npm users +npm update eslint@3.x babel-eslint@7 +``` + +Ensure you have the following line inside your `.eslintrc`: + +```json +"parser": "babel-eslint" +``` + +That's it! + +Note that `babel-eslint` is not officially supported by ESLint. We'll be looking into adding support for fragments to ESLint 4.x itself in the coming weeks (see [issue #9662](https://github.com/eslint/eslint/issues/9662)). + +### Editor Support + +It may take a while for fragment syntax to be supported in your text editor. Please be patient as the community works to adopt the latest changes. In the meantime, you may see errors or inconsistent highlighting if your editor does not yet support fragment syntax. Generally, these errors can be safely ignored. + +#### TypeScript Editor Support + +If you're a TypeScript user -- great news! Editor support for JSX fragments is already available in [Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48593), [Visual Studio 2017](https://www.microsoft.com/en-us/download/details.aspx?id=55258), [Visual Studio Code](https://code.visualstudio.com/updates/v1_19#_jsx-fragment-syntax) and [Sublime Text via Package Control](https://packagecontrol.io/packages/TypeScript). + +### Other Tools + +For other tools, please check with the corresponding documentation to check if there is support available. However, if you're blocked by your tooling, you can always start with using the `` component and perform a codemod later to replace it with the shorthand syntax when the appropriate support is available. + +## Installation + +React v16.2.0 is available on the npm registry. + +To install React 16 with Yarn, run: + +```bash +yarn add react@^16.2.0 react-dom@^16.2.0 +``` + +To install React 16 with npm, run: + +```bash +npm install --save react@^16.2.0 react-dom@^16.2.0 +``` + +We also provide UMD builds of React via a CDN: + +```html + + +``` + +Refer to the documentation for [detailed installation instructions](/docs/installation.html). + +## Changelog + +### React + +* Add `Fragment` as named export to React. ([@clemmy](https://github.com/clemmy) in [#10783](https://github.com/facebook/react/pull/10783)) +* Support experimental Call/Return types in `React.Children` utilities. ([@MatteoVH](https://github.com/MatteoVH) in [#11422](https://github.com/facebook/react/pull/11422)) + +### React DOM + +* Fix radio buttons not getting checked when using multiple lists of radios. ([@landvibe](https://github.com/landvibe) in [#11227](https://github.com/facebook/react/pull/11227)) +* Fix radio buttons not receiving the `onChange` event in some cases. ([@jquense](https://github.com/jquense) in [#11028](https://github.com/facebook/react/pull/11028)) + +### React Test Renderer + +* Fix `setState()` callback firing too early when called from `componentWillMount`. ([@accordeiro](https://github.com/accordeiro) in [#11507](https://github.com/facebook/react/pull/11507)) + +### React Reconciler + +* Expose `react-reconciler/reflection` with utilities useful to custom renderers. ([@rivenhk](https://github.com/rivenhk) in [#11683](https://github.com/facebook/react/pull/11683)) + +### Internal Changes + +* Many tests were rewritten against the public API. Big thanks to [everyone who contributed](https://github.com/facebook/react/issues/11299)! + +## Acknowledgments + +This release was made possible by our open source contributors. A big thanks to everyone who filed issues, contributed to syntax discussions, reviewed pull requests, added support for JSX fragments in third party libraries, and more! + +Special thanks to the [TypeScript](https://www.typescriptlang.org/) and [Flow](https://flow.org/) teams, as well as the [Babel](https://babeljs.io/) maintainers, who helped make tooling support for the new syntax go seamlessly. + +Thanks to [Gajus Kuizinas](https://github.com/gajus/) and other contributors who prototyped the `Fragment` component in open source. diff --git a/content/blog/2017-12-07-introducing-the-react-rfc-process.md b/content/blog/2017-12-07-introducing-the-react-rfc-process.md new file mode 100644 index 00000000000..595b7f37c94 --- /dev/null +++ b/content/blog/2017-12-07-introducing-the-react-rfc-process.md @@ -0,0 +1,40 @@ +--- +title: "Introducing the React RFC Process" +author: [acdlite] +--- + +We're adopting an RFC ("request for comments") process for contributing ideas to React. + +Inspired by [Yarn](https://github.com/yarnpkg/rfcs), [Ember](https://github.com/emberjs/rfcs), and [Rust](https://github.com/rust-lang/rfcs), the goal is to allow React core team members and community members to collaborate on the design of new features. It's also intended to provide a clear path for ideas to enter the project: + +- Create an RFC document detailing your proposal. +- Submit a PR to the [RFC repository](https://github.com/reactjs/rfcs). +- Incorporate feedback into the proposal. +- After discussion, the core team may or may not accept the RFC. +- If the RFC is accepted, the PR is merged. + +RFCs are accepted when they are approved for implementation in React. A more thorough description of the process is available in the repository's [README](https://github.com/reactjs/rfcs/blob/master/README.md). The exact details may be refined in the future. + +## Who Can Submit RFCs? + +Anyone! No knowledge of React's internals is required, nor are you expected to implement the proposal yourself. + +As with our other repositories, we do ask that you complete a [Contributor License Agreement](https://github.com/reactjs/rfcs#contributor-license-agreement-cla) before we can accept your PR. + +## What Types of Changes Should Be Submitted As RFCs? + +Generally, any idea that would benefit from additional review or design before being implemented is a good candidate for an RFC. As a rule of thumb, this means any proposal that adds, changes, or removes a React API. + +Not every change must go through the RFC process. Bug fixes or performance improvements that don't touch the API can be submitted directly to the main library. + +We now have several repositories where you can submit contributions to React: + +- **Issues, bugfixes, and code changes to the main library**: [facebook/react](https://github.com/facebook/react) +- **Website and documentation**: [reactjs/reactjs.org](https://github.com/reactjs/reactjs.org) +- **Ideas for changes that need additional review before being implemented**: [reactjs/rfcs](https://github.com/reactjs/rfcs) + +## RFC for A New Context API + +Coinciding with the launch of our RFC process, we've submitted a [proposal for a new version of context](https://github.com/reactjs/rfcs/pull/2). The proposal has already received many valuable comments from the community that we will incorporate into the design of the new API. + +The context PR is a good example of how a typical RFC should be structured. We're excited to start receiving your proposals! diff --git a/content/blog/2017-12-15-improving-the-repository-infrastructure.md b/content/blog/2017-12-15-improving-the-repository-infrastructure.md new file mode 100644 index 00000000000..938a5305706 --- /dev/null +++ b/content/blog/2017-12-15-improving-the-repository-infrastructure.md @@ -0,0 +1,389 @@ +--- +title: "Behind the Scenes: Improving the Repository Infrastructure" +author: [gaearon, bvaughn] +--- + +As we worked on [React 16](/blog/2017/09/26/react-v16.0.html), we revamped the folder structure and much of the build tooling in the React repository. Among other things, we introduced projects such as [Rollup](https://rollupjs.org/), [Prettier](https://prettier.io/), and [Google Closure Compiler](https://developers.google.com/closure/compiler/) into our workflow. People often ask us questions about how we use those tools. In this post, we would like to share some of the changes that we've made to our build and test infrastructure in 2017, and what motivated them. + +While these changes helped us make React better, they don't affect most React users directly. However, we hope that blogging about them might help other library authors solve similar problems. Our contributors might also find these notes helpful! + +## Formatting Code with Prettier + +React was one of the first large repositories to [fully embrace](https://github.com/facebook/react/pull/9101) opinionated automatic code formatting with [Prettier](https://prettier.io/). Our current Prettier setup consists of: + +* A local [`yarn prettier`](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/package.json#L115) script that [uses the Prettier Node API](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/prettier/index.js#L71-L77) to format files in place. We typically run it before committing changes. It is fast because it only checks the [files changed since diverging from remote master](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/shared/listChangedFiles.js#L29-L33). +* A script that [runs Prettier](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/prettier/index.js#L79-L90) as part of our [continuous integration checks](https://github.com/facebook/react/blob/d906de7f602df810c38aa622c83023228b047db6/scripts/circleci/test_entry_point.sh#L10). It won't attempt to overwrite the files, but instead will fail the build if any file differs from the Prettier output for that file. This ensures that we can't merge a pull request unless it has been fully formatted. + +Some team members have also set up the [editor integrations](https://prettier.io/docs/en/editors.html). Our experience with Prettier has been fantastic, and we recommend it to any team that writes JavaScript. + +## Restructuring the Monorepo + +Ever since React was split into packages, it has been a [monorepo](https://danluu.com/monorepo/): a set of packages under the umbrella of a single repository. This made it easier to coordinate changes and share the tooling, but our folder structure was deeply nested and difficult to understand. It was not clear which files belonged to which package. After releasing React 16, we've decided to completely reorganize the repository structure. Here is how we did it. + +### Migrating to Yarn Workspaces + +The Yarn package manager [introduced a feature called Workspaces](https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/) a few months ago. This feature lets you tell Yarn where your monorepo's packages are located in the source tree. Every time you run `yarn`, in addition to installing your dependencies it also sets up the symlinks that point from your project's `node_modules` to the source folders of your packages. + +Thanks to Workspaces, absolute imports between our own packages (such as importing `react` from `react-dom`) "just work" with any tools that support the Node resolution mechanism. The only problem we encountered was Jest not running the transforms inside the linked packages, but we [found a fix](https://github.com/facebook/jest/pull/4761), and it was merged into Jest. + +To enable Yarn Workspaces, we added `"workspaces": ["packages/*"]` to our [`package.json`](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/package.json#L4-L6), and moved all the code into [top-level `packages/*` folders](https://github.com/facebook/react/tree/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages), each with its own `package.json` file. + +Each package is structured in a similar way. For every public API entry point such as `react-dom` or `react-dom/server`, there is a [file](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/react-dom/index.js) in the package root folder that re-exports the implementation from the [`/src/`](https://github.com/facebook/react/tree/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/react-dom/src) subfolder. The decision to point entry points to the source rather than to the built versions was intentional. Typically, we re-run a subset of tests after every change during development. Having to build the project to run a test would have been prohibitively slow. When we publish packages to npm, we replace these entry points with files in the [`/npm/`](https://github.com/facebook/react/tree/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/react-dom/npm) folder that point to the build artifacts. + +Not all packages have to be published on npm. For example, we keep some utilities that are tiny enough and can be safely duplicated in a [pseudo-package called `shared`](https://github.com/facebook/react/tree/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/shared). Our bundler is configured to [only treat `dependencies` declared from `package.json` as externals](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/build.js#L326-L329) so it happily bundles the `shared` code into `react` and `react-dom` without leaving any references to `shared/` in the build artifacts. So you can use Yarn Workspaces even if you don't plan to publish actual npm packages! + +### Removing the Custom Module System + +In the past, we used a non-standard module system called "Haste" that lets you import any file from any other file by its unique `@providesModule` directive no matter where it is in the tree. It neatly avoids the problem of deep relative imports with paths like `../../../../` and is great for the product code. However, this makes it hard to understand the dependencies between packages. We also had to resort to hacks to make it work with different tools. + +We decided to [remove Haste](https://github.com/facebook/react/pull/11303) and use the Node resolution with relative imports instead. To avoid the problem of deep relative paths, we have [flattened our repository structure](https://github.com/facebook/react/pull/11304) so that it goes at most one level deep inside each package: + +``` +|-react +| |-npm +| |-src +|-react-dom +| |-npm +| |-src +| | |-client +| | |-events +| | |-server +| | |-shared +``` + +This way, the relative paths can only contain one `./` or `../` followed by the filename. If one package needs to import something from another package, it can do so with an absolute import from a top-level entry point. + +In practice, we still have [some cross-package "internal" imports](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/react-dom/src/client/ReactDOMFiberComponent.js#L10-L11) that violate this principle, but they're explicit, and we plan to gradually get rid of them. + +## Compiling Flat Bundles + +Historically, React was distributed in two different formats: as a single-file build that you can add as a ` + +Going through the fixtures is still a lot of work, and we are considering automating some of it. Still, the fixture app is invaluable even as documentation for the existing behavior and all the edge cases and browser bugs that React currently handles. Having it gives us confidence in making significant changes to the logic without breaking important use cases. Another improvement we're considering is to have a GitHub bot build and deploy the fixtures automatically for every pull request that touches the relevant files so anyone can help with browser testing. + +### Preventing Infinite Loops + +The React 16 codebase contains many `while` loops. They let us avoid the dreaded deep stack traces that occurred with earlier versions of React, but can make development of React really difficult. Every time there is a mistake in an exit condition our tests would just hang, and it took a while to figure out which of the loops is causing the issue. + +Inspired by the [strategy adopted by Repl.it](https://repl.it/site/blog/infinite-loops), we have added a [Babel plugin that prevents infinite loops](https://github.com/facebook/react/blob/d906de7f602df810c38aa622c83023228b047db6/scripts/babel/transform-prevent-infinite-loops.js) in the test environment. If some loop continues for more than the maximum allowed number of iterations, we throw an error and immediately fail it so that Jest can display where exactly this happened. + +This approach has a pitfall. If an error thrown from the Babel plugin gets caught and ignored up the call stack, the test will pass even though it has an infinite loop. This is really, really bad. To solve this problem, we [set a global field](https://github.com/facebook/react/blob/d906de7f602df810c38aa622c83023228b047db6/scripts/babel/transform-prevent-infinite-loops.js#L26-L30) before throwing the error. Then, after every test run, we [rethrow that error if the global field has been set](https://github.com/facebook/react/blob/d906de7f602df810c38aa622c83023228b047db6/scripts/jest/setupTests.js#L42-L56). This way any infinite loop will cause a test failure, no matter whether the error from the Babel plugin was caught or not. + +## Customizing the Build + +There were a few things that we had to fine-tune after introducing our new build process. It took us a while to figure them out, but we're moderately happy with the solutions that we arrived at. + +### Dead Code Elimination + +The combination of Rollup and Google Closure Compiler already gets us pretty far in terms of stripping development-only code in production bundles. We [replace](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/build.js#L223-L226) the `__DEV__` literal with a boolean constant during the build, and both Rollup together and Google Closure Compiler can strip out the `if (false) {}` code branches and even some more sophisticated patterns. However, there is one particularly nasty case: + +```js +import warning from 'fbjs/lib/warning'; + +if (__DEV__) { + warning(false, 'Blimey!'); +} +``` + +This pattern is very common in the React source code. However `fbjs/lib/warning` is an external import that isn't being bundled by Rollup for the CommonJS bundle. Therefore, even if `warning()` call ends up being removed, Rollup doesn't know whether it's safe to remove to the import itself. What if the module performs a side effect during initialization? Then removing it would not be safe. + +To solve this problem, we use the [`treeshake.pureExternalModules` Rollup option](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/build.js#L338-L340) which takes an array of modules that we can guarantee don't have side effects. This lets Rollup know that an import to `fbjs/lib/warning` is safe to completely strip out if its value is not being used. However, if it *is* being used (e.g. if we decide to add warnings in production), the import will be preserved. That's why this approach is safer than replacing modules with empty shims. + +When we optimize something, we need to ensure it doesn't regress in the future. What if somebody introduces a new development-only import of an external module, and not realize they also need to add it to `pureExternalModules`? Rollup prints a warning in such cases but we've [decided to fail the build completely](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/build.js#L395-L412) instead. This forces the person adding a new external development-only import to [explicitly specify whether it has side effects or not](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/modules.js#L10-L22) every time. + +### Forking Modules + +In some cases, different bundles need to contain slightly different code. For example, React Native bundles have a different error handling mechanism that shows a redbox instead of printing a message to the console. However, it can be very inconvenient to thread these differences all the way through the calling modules. + +Problems like this are often solved with runtime configuration. However, sometimes it is impossible: for example, the React DOM bundles shouldn't even attempt to import the React Native redbox helpers. It is also unfortunate to bundle the code that never gets used in a particular environment. + +Another solution is to use dynamic dependency injection. However, it often produces code that is hard to understand, and may cause cyclical dependencies. It also defies some optimization opportunities. + +From the code point of view, ideally we just want to "redirect" a module to its different "forks" for specific bundles. The "forks" have the exact same API as the original modules, but do something different. We found this mental model very intuitive, and [created a fork configuration file](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/forks.js) that specifies how the original modules map to their forks, and the conditions under which this should happen. + +For example, this fork config entry specifies different [feature flags](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/shared/ReactFeatureFlags.js) for different bundles: + +```js +'shared/ReactFeatureFlags': (bundleType, entry) => { + switch (entry) { + case 'react-native-renderer': + return 'shared/forks/ReactFeatureFlags.native.js'; + case 'react-cs-renderer': + return 'shared/forks/ReactFeatureFlags.native-cs.js'; + default: + switch (bundleType) { + case FB_DEV: + case FB_PROD: + return 'shared/forks/ReactFeatureFlags.www.js'; + } + } + return null; +}, +``` + +During the build, [our custom Rollup plugin](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/scripts/rollup/plugins/use-forks-plugin.js#L40) replaces modules with their forks if the conditions have matched. Since both the original modules and the forks are written as ES Modules, Rollup and Google Closure Compiler can inline constants like numbers or booleans, and thus efficiently eliminate dead code for disabled feature flags. In tests, when necessary, we [use `jest.mock()`](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/react-cs-renderer/src/__tests__/ReactNativeCS-test.internal.js#L15-L17) to point the module to the appropriate forked version. + +As a bonus, we might want to verify that the export types of the original modules match the export types of the forks exactly. We can use a [slightly odd but totally working Flow trick](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/shared/forks/ReactFeatureFlags.native.js#L32-L36) to accomplish this: + +```js +import typeof * as FeatureFlagsType from 'shared/ReactFeatureFlags'; +import typeof * as FeatureFlagsShimType from './ReactFeatureFlags.native'; +type Check<_X, Y: _X, X: Y = _X> = null; +(null: Check); +``` + +This works by essentially forcing Flow to verify that two types are assignable to each other (and thus are equivalent). Now if we modify the exports of either the original module or the fork without changing the other file, the type check will fail. This might be a little goofy but we found this helpful in practice. + +To conclude this section, it is important to note that you can't specify your own module forks if you consume React from npm. This is intentional because none of these files are public API, and they are not covered by the [semver](https://semver.org/) guarantees. However, you are always welcome to build React from master or even fork it if you don't mind the instability and the risk of divergence. We hope that this writeup was still helpful in documenting one possible approach to targeting different environments from a single JavaScript library. + +### Tracking Bundle Size + +As a final build step, we now [record build sizes for all bundles](https://github.com/facebook/react/blob/d906de7f602df810c38aa622c83023228b047db6/scripts/rollup/build.js#L264-L272) and write them to a file that [looks like this](https://github.com/facebook/react/blob/d906de7f602df810c38aa622c83023228b047db6/scripts/rollup/results.json). When you run `yarn build`, it prints a table with the results: + +
+ +Build results after running GCC + +*(It doesn't always look as good as this. This was the commit that migrated React from Uglify to Google Closure Compiler.)* + +Keeping the file sizes committed for everyone to see was helpful for tracking size changes and motivating people to find optimization opportunities. + +We haven't been entirely happy with this strategy because the JSON file often causes merge conflicts on larger branches. Updating it is also not currently enforced so it gets out of date. In the future, we're considering integrating a bot that would comment on pull requests with the size changes. + +## Simplifying the Release Process + +We like to release updates to the open source community often. Unfortunately, the old process of creating a release was slow and would typically take an entire day. After some changes to this process, we're now able to do a full release in less than an hour. Here's what we changed. + +### Branching Strategy + +Most of the time spent in the old release process was due to our branching strategy. The `master` branch was assumed to be unstable and would often contain breaking changes. Releases were done from a `stable` branch, and changes were manually cherry-picked into this branch prior to a release. We had [tooling to help automate](https://github.com/facebook/react/pull/7330) some of this process, but it was still [pretty complicated to use](https://github.com/facebook/react/blob/b5a2a1349d6e804d534f673612357c0be7e1d701/scripts/release-manager/Readme.md). + +As of version 16, we now release from the `master` branch. Experimental features and breaking changes are allowed, but must be hidden behind [feature flags](https://github.com/facebook/react/blob/cc52e06b490e0dc2482b345aa5d0d65fae931095/packages/shared/ReactFeatureFlags.js) so they can be removed during the build process. The new flat bundles and dead code elimination make it possible for us to do this without fear of leaking unwanted code into open source builds. + +### Automated Scripts + +After changing to a stable `master`, we created a new [release process checklist](https://github.com/facebook/react/issues/10620). Although much simpler than the previous process, this still involved dozens of steps and forgetting one could result in a broken release. + +To address this, we created a new [automated release process](https://github.com/facebook/react/pull/11223) that is [much easier to use](https://github.com/facebook/react/tree/master/scripts/release#react-release-script) and has several built-in checks to ensure that we release a working build. The new process is split into two steps: _build_ and _publish_. Here's what it looks like the first time you run it: + +![Release Script overview](../images/blog/release-script-build-overview.png) + +The _build_ step does most of the work- verifying permissions, running tests, and checking CI status. Once it finishes, it prints a reminder to update the CHANGELOG and to verify the bundle using the [manual fixtures](#creating-manual-test-fixtures) described above. + +![Release Script build confirmation screen](../images/blog/release-script-build-confirmation.png) + +All that's left is to tag and publish the release to NPM using the _publish_ script. + +![Release Script publish confirmation screen](../images/blog/release-script-publish-confirmation.png) + +(You may have noticed a `--dry` flag in the screenshots above. This flag allows us to run a release, end-to-end, without actually publishing to NPM. This is useful when working on the release script itself.) + +## In Conclusion + +Did this post inspire you to try some of these ideas in your own projects? We certainly hope so! If you have other ideas about how React build, test, or contribution workflow could be improved, please let us know on [our issue tracker](https://github.com/facebook/react/issues). + +You can find the related issues by the [build infrastructure label](https://github.com/facebook/react/labels/Component%3A%20Build%20Infrastructure). These are often great first contribution opportunities! + +## Acknowledgements + +We would like to thank: + +* [Rich Harris](https://github.com/Rich-Harris) and [Lukas Taegert](https://github.com/lukastaegert) for maintaining Rollup and helping us integrate it. +* [Dimitris Vardoulakis](https://github.com/dimvar), [Chad Killingsworth](https://github.com/ChadKillingsworth), and [Tyler Breisacher](https://github.com/MatrixFrog) for their work on Google Closure Compiler and timely advice. +* [Adrian Carolli](https://github.com/watadarkstar), [Adams Au](https://github.com/rivenhk), [Alex Cordeiro](https://github.com/accordeiro), [Jordan Tepper](https://github.com/HeroProtagonist), [Johnson Shi](https://github.com/sjy), [Soo Jae Hwang](https://github.com/misoguy), [Joe Lim](https://github.com/xjlim), [Yu Tian](https://github.com/yu-tian113), and others for helping prototype and implement some of these and other improvements. +* [Anushree Subramani](https://github.com/anushreesubramani), [Abid Uzair](https://github.com/abiduzz420), [Sotiris Kiritsis](https://github.com/skiritsis), [Tim Jacobi](https://github.com/timjacobi), [Anton Arboleda](https://github.com/aarboleda1), [Jeremias Menichelli](https://github.com/jeremenichelli), [Audy Tanudjaja](https://github.com/audyodi), [Gordon Dent](https://github.com/gordyd), [Iacami Gevaerd +](https://github.com/enapupe), [Lucas Lentz](https://github.com/sadpandabear), [Jonathan Silvestri](https://github.com/silvestrijonathan), [Mike Wilcox](https://github.com/mjw56), [Bernardo Smaniotto](https://github.com/smaniotto), [Douglas Gimli](https://github.com/douglasgimli), [Ethan Arrowood](https://github.com/ethan-arrowood), and others for their help porting the React test suite to use the public API. diff --git a/content/blog/2018-03-01-sneak-peek-beyond-react-16.md b/content/blog/2018-03-01-sneak-peek-beyond-react-16.md new file mode 100644 index 00000000000..1ab9f4db7fe --- /dev/null +++ b/content/blog/2018-03-01-sneak-peek-beyond-react-16.md @@ -0,0 +1,24 @@ +--- +title: "Sneak Peek: Beyond React 16" +author: [sophiebits] +--- + +[Dan Abramov](https://twitter.com/dan_abramov) from our team just spoke at [JSConf Iceland 2018](https://2018.jsconf.is/) with a preview of some new features we've been working on in React. The talk opens with a question: "With vast differences in computing power and network speed, how do we deliver the best user experience for everyone?" + +Here's the video courtesy of JSConf Iceland: + +
+ + + +I think you'll enjoy the talk more if you stop reading here and just watch the video. If you don't have time to watch, a (very) brief summary follows. + +## About the Two Demos + +On the first demo, Dan says: "We've built a generic way to ensure that high-priority updates don't get blocked by a low-priority update, called **time slicing**. If my device is fast enough, it feels almost like it's synchronous; if my device is slow, the app still feels responsive. It adapts to the device thanks to the [requestIdleCallback](https://developers.google.com/web/updates/2015/08/using-requestidlecallback) API. Notice that only the final state was displayed; the rendered screen is always consistent and we don't see visual artifacts of slow rendering causing a janky user experience." + +On the second demo, Dan explains: "We've built a generic way for components to suspend rendering while they load async data, which we call **suspense**. You can pause any state update until the data is ready, and you can add async loading to any component deep in the tree without plumbing all the props and state through your app and hoisting the logic. On a fast network, updates appear very fluid and instantaneous without a jarring cascade of spinners that appear and disappear. On a slow network, you can intentionally design which loading states the user should see and how granular or coarse they should be, instead of showing spinners based on how the code is written. The app stays responsive throughout." + +"Importantly, this is still the React you know. This is still the declarative component paradigm that you probably like about React." + +We can't wait to release these new async rendering features later this year. Follow this blog and [@reactjs on Twitter](https://twitter.com/reactjs) for updates. diff --git a/content/blog/2018-03-27-update-on-async-rendering.md b/content/blog/2018-03-27-update-on-async-rendering.md new file mode 100644 index 00000000000..080dc2febd0 --- /dev/null +++ b/content/blog/2018-03-27-update-on-async-rendering.md @@ -0,0 +1,216 @@ +--- +title: Update on Async Rendering +author: [bvaughn] +--- + +For over a year, the React team has been working to implement asynchronous rendering. Last month during his talk at JSConf Iceland, [Dan unveiled some of the exciting new possibilities async rendering unlocks](/blog/2018/03/01/sneak-peek-beyond-react-16.html). Now we'd like to share with you some of the lessons we've learned while working on these features, and some recipes to help prepare your components for async rendering when it launches. + +One of the biggest lessons we've learned is that some of our legacy component lifecycles tend to encourage unsafe coding practices. They are: + +* `componentWillMount` +* `componentWillReceiveProps` +* `componentWillUpdate` + +These lifecycle methods have often been misunderstood and subtly misused; furthermore, we anticipate that their potential misuse may be more problematic with async rendering. Because of this, we will be adding an "UNSAFE_" prefix to these lifecycles in an upcoming release. (Here, "unsafe" refers not to security but instead conveys that code using these lifecycles will be more likely to have bugs in future versions of React, especially once async rendering is enabled.) + +## Gradual Migration Path + +[React follows semantic versioning](/blog/2016/02/19/new-versioning-scheme.html), so this change will be gradual. Our current plan is: + +* **16.3**: Introduce aliases for the unsafe lifecycles, `UNSAFE_componentWillMount`, `UNSAFE_componentWillReceiveProps`, and `UNSAFE_componentWillUpdate`. (Both the old lifecycle names and the new aliases will work in this release.) +* **A future 16.x release**: Enable deprecation warning for `componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate`. (Both the old lifecycle names and the new aliases will work in this release, but the old names will log a DEV-mode warning.) +* **17.0**: Remove `componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate` . (Only the new "UNSAFE_" lifecycle names will work from this point forward.) + +**Note that if you're a React application developer, you don't have to do anything about the legacy methods yet. The primary purpose of the upcoming version 16.3 release is to enable open source project maintainers to update their libraries in advance of any deprecation warnings. Those warnings will not be enabled until a future 16.x release.** + +We maintain over 50,000 React components at Facebook, and we don't plan to rewrite them all immediately. We understand that migrations take time. We will take the gradual migration path along with everyone in the React community. + +--- + +## Migrating from Legacy Lifecycles + +If you'd like to start using the new component APIs introduced in React 16.3 (or if you're a maintainer looking to update your library in advance) here are a few examples that we hope will help you to start thinking about components a bit differently. Over time, we plan to add additional "recipes" to our documentation that show how to perform common tasks in a way that avoids the problematic lifecycles. + +Before we begin, here's a quick overview of the lifecycle changes planned for version 16.3: +* We are **adding the following lifecycle aliases**: `UNSAFE_componentWillMount`, `UNSAFE_componentWillReceiveProps`, and `UNSAFE_componentWillUpdate`. (Both the old lifecycle names and the new aliases will be supported.) +* We are **introducing two new lifecycles**, static `getDerivedStateFromProps` and `getSnapshotBeforeUpdate`. + +### New lifecycle: `getDerivedStateFromProps` + +`embed:update-on-async-rendering/definition-getderivedstatefromprops.js` + +The new static `getDerivedStateFromProps` lifecycle is invoked after a component is instantiated as well as when it receives new props. It can return an object to update `state`, or `null` to indicate that the new `props` do not require any `state` updates. + +Together with `componentDidUpdate`, this new lifecycle should cover all use cases for the legacy `componentWillReceiveProps`. + +### New lifecycle: `getSnapshotBeforeUpdate` + +`embed:update-on-async-rendering/definition-getsnapshotbeforeupdate.js` + +The new `getSnapshotBeforeUpdate` lifecycle is called right before mutations are made (e.g. before the DOM is updated). The return value for this lifecycle will be passed as the third parameter to `componentDidUpdate`. (This lifecycle isn't often needed, but can be useful in cases like manually preserving scroll position during rerenders.) + +Together with `componentDidUpdate`, this new lifecycle should cover all use cases for the legacy `componentWillUpdate`. + +You can find their type signatures [in this gist](https://gist.github.com/gaearon/88634d27abbc4feeb40a698f760f3264). + +We'll look at examples of how both of these lifecycles can be used below. + +## Examples +- [Initializing state](#initializing-state) +- [Fetching external data](#fetching-external-data) +- [Adding event listeners (or subscriptions)](#adding-event-listeners-or-subscriptions) +- [Updating `state` based on props](#updating-state-based-on-props) +- [Invoking external callbacks](#invoking-external-callbacks) +- [Side effects on props change](#side-effects-on-props-change) +- [Fetching external data when props change](#fetching-external-data-when-props-change) +- [Reading DOM properties before an update](#reading-dom-properties-before-an-update) + +> Note +> +> For brevity, the examples below are written using the experimental class properties transform, but the same migration strategies apply without it. + +### Initializing state + +This example shows a component with `setState` calls inside of `componentWillMount`: +`embed:update-on-async-rendering/initializing-state-before.js` + +The simplest refactor for this type of component is to move state initialization to the constructor or to a property initializer, like so: +`embed:update-on-async-rendering/initializing-state-after.js` + +### Fetching external data + +Here is an example of a component that uses `componentWillMount` to fetch external data: +`embed:update-on-async-rendering/fetching-external-data-before.js` + +The above code is problematic for both server rendering (where the external data won't be used) and the upcoming async rendering mode (where the request might be initiated multiple times). + +The recommended upgrade path for most use cases is to move data-fetching into `componentDidMount`: +`embed:update-on-async-rendering/fetching-external-data-after.js` + +There is a common misconception that fetching in `componentWillMount` lets you avoid the first empty rendering state. In practice this was never true because React has always executed `render` immediately after `componentWillMount`. If the data is not available by the time `componentWillMount` fires, the first `render` will still show a loading state regardless of where you initiate the fetch. This is why moving the fetch to `componentDidMount` has no perceptible effect in the vast majority of cases. + +> Note +> +> Some advanced use-cases (e.g. libraries like Relay) may want to experiment with eagerly prefetching async data. An example of how this can be done is available [here](https://gist.github.com/bvaughn/89700e525ff423a75ffb63b1b1e30a8f). +> +> In the longer term, the canonical way to fetch data in React components will likely be based on the “suspense” API [introduced at JSConf Iceland](/blog/2018/03/01/sneak-peek-beyond-react-16.html). Both simple data fetching solutions and libraries like Apollo and Relay will be able to use it under the hood. It is significantly less verbose than either of the above solutions, but will not be finalized in time for the 16.3 release. +> +> When supporting server rendering, it's currently necessary to provide the data synchronously – `componentWillMount` was often used for this purpose but the constructor can be used as a replacement. The upcoming suspense APIs will make async data fetching cleanly possible for both client and server rendering. + +### Adding event listeners (or subscriptions) + +Here is an example of a component that subscribes to an external event dispatcher when mounting: +`embed:update-on-async-rendering/adding-event-listeners-before.js` + +Unfortunately, this can cause memory leaks for server rendering (where `componentWillUnmount` will never be called) and async rendering (where rendering might be interrupted before it completes, causing `componentWillUnmount` not to be called). + +People often assume that `componentWillMount` and `componentWillUnmount` are always paired, but that is not guaranteed. Only once `componentDidMount` has been called does React guarantee that `componentWillUnmount` will later be called for clean up. + +For this reason, the recommended way to add listeners/subscriptions is to use the `componentDidMount` lifecycle: +`embed:update-on-async-rendering/adding-event-listeners-after.js` + +Sometimes it is important to update subscriptions in response to property changes. If you're using a library like Redux or MobX, the library's container component should handle this for you. For application authors, we've created a small library, [`create-subscription`](https://github.com/facebook/react/tree/master/packages/create-subscription), to help with this. We'll publish it along with React 16.3. + +Rather than passing a subscribable `dataSource` prop as we did in the example above, we could use `create-subscription` to pass in the subscribed value: + +`embed:update-on-async-rendering/adding-event-listeners-create-subscription.js` + +> Note +> +> Libraries like Relay/Apollo should manage subscriptions manually with the same techniques as `create-subscription` uses under the hood (as referenced [here](https://gist.github.com/bvaughn/d569177d70b50b58bff69c3c4a5353f3)) in a way that is most optimized for their library usage. + +### Updating `state` based on `props` + +Here is an example of a component that uses the legacy `componentWillReceiveProps` lifecycle to update `state` based on new `props` values: +`embed:update-on-async-rendering/updating-state-from-props-before.js` + +Although the above code is not problematic in itself, the `componentWillReceiveProps` lifecycle is often mis-used in ways that _do_ present problems. Because of this, the method will be deprecated. + +As of version 16.3, the recommended way to update `state` in response to `props` changes is with the new `static getDerivedStateFromProps` lifecycle. (That lifecycle is called when a component is created and each time it receives new props): +`embed:update-on-async-rendering/updating-state-from-props-after.js` + +You may notice in the example above that `props.currentRow` is mirrored in state (as `state.lastRow`). This enables `getDerivedStateFromProps` to access the previous props value in the same way as is done in `componentWillReceiveProps`. + +You may wonder why we don't just pass previous props as a parameter to `getDerivedStateFromProps`. We considered this option when designing the API, but ultimately decided against it for two reasons: +* A `prevProps` parameter would be null the first time `getDerivedStateFromProps` was called (after instantiation), requiring an if-not-null check to be added any time `prevProps` was accessed. +* Not passing the previous props to this function is a step toward freeing up memory in future versions of React. (If React does not need to pass previous props to lifecycles, then it does not need to keep the previous `props` object in memory.) + +> Note +> +> If you're writing a shared component, the [`react-lifecycles-compat`](https://github.com/reactjs/react-lifecycles-compat) polyfill enables the new `getDerivedStateFromProps` lifecycle to be used with older versions of React as well. [Learn more about how to use it below.](#open-source-project-maintainers) + +### Invoking external callbacks + +Here is an example of a component that calls an external function when its internal state changes: +`embed:update-on-async-rendering/invoking-external-callbacks-before.js` + +Sometimes people use `componentWillUpdate` out of a misplaced fear that by the time `componentDidUpdate` fires, it is "too late" to update the state of other components. This is not the case. React ensures that any `setState` calls that happen during `componentDidMount` and `componentDidUpdate` are flushed before the user sees the updated UI. In general, it is better to avoid cascading updates like this, but in some cases they are necessary (for example, if you need to position a tooltip after measuring the rendered DOM element). + +Either way, it is unsafe to use `componentWillUpdate` for this purpose in async mode, because the external callback might get called multiple times for a single update. Instead, the `componentDidUpdate` lifecycle should be used since it is guaranteed to be invoked only once per update: +`embed:update-on-async-rendering/invoking-external-callbacks-after.js` + +### Side effects on props change + +Similar to the [example above](#invoking-external-callbacks), sometimes components have side effects when `props` change. + +`embed:update-on-async-rendering/side-effects-when-props-change-before.js` + +Like `componentWillUpdate`, `componentWillReceiveProps` might get called multiple times for a single update. For this reason it is important to avoid putting side effects in this method. Instead, `componentDidUpdate` should be used since it is guaranteed to be invoked only once per update: + +`embed:update-on-async-rendering/side-effects-when-props-change-after.js` + +### Fetching external data when `props` change + +Here is an example of a component that fetches external data based on `props` values: +`embed:update-on-async-rendering/updating-external-data-when-props-change-before.js` + +The recommended upgrade path for this component is to move data updates into `componentDidUpdate`. You can also use the new `getDerivedStateFromProps` lifecycle to clear stale data before rendering the new props: +`embed:update-on-async-rendering/updating-external-data-when-props-change-after.js` + +> Note +> +> If you're using an HTTP library that supports cancellation, like [axios](https://www.npmjs.com/package/axios), then it's simple to cancel an in-progress request when unmounting. For native Promises, you can use an approach like [the one shown here](https://gist.github.com/bvaughn/982ab689a41097237f6e9860db7ca8d6). + +### Reading DOM properties before an update + +Here is an example of a component that reads a property from the DOM before an update in order to maintain scroll position within a list: +`embed:update-on-async-rendering/react-dom-properties-before-update-before.js` + +In the above example, `componentWillUpdate` is used to read the DOM property. However with async rendering, there may be delays between "render" phase lifecycles (like `componentWillUpdate` and `render`) and "commit" phase lifecycles (like `componentDidUpdate`). If the user does something like resize the window during this time, the `scrollHeight` value read from `componentWillUpdate` will be stale. + +The solution to this problem is to use the new "commit" phase lifecycle, `getSnapshotBeforeUpdate`. This method gets called _immediately before_ mutations are made (e.g. before the DOM is updated). It can return a value for React to pass as a parameter to `componentDidUpdate`, which gets called _immediately after_ mutations. + +The two lifecycles can be used together like this: + +`embed:update-on-async-rendering/react-dom-properties-before-update-after.js` + +> Note +> +> If you're writing a shared component, the [`react-lifecycles-compat`](https://github.com/reactjs/react-lifecycles-compat) polyfill enables the new `getSnapshotBeforeUpdate` lifecycle to be used with older versions of React as well. [Learn more about how to use it below.](#open-source-project-maintainers) + +## Other scenarios + +While we tried to cover the most common use cases in this post, we recognize that we might have missed some of them. If you are using `componentWillMount`, `componentWillUpdate`, or `componentWillReceiveProps` in ways that aren't covered by this blog post, and aren't sure how to migrate off these legacy lifecycles, please [file a new issue against our documentation](https://github.com/reactjs/reactjs.org/issues/new) with your code examples and as much background information as you can provide. We will update this document with new alternative patterns as they come up. + +## Open source project maintainers + +Open source maintainers might be wondering what these changes mean for shared components. If you implement the above suggestions, what happens with components that depend on the new static `getDerivedStateFromProps` lifecycle? Do you also have to release a new major version and drop compatibility for React 16.2 and older? + +Fortunately, you do not! + +When React 16.3 is published, we'll also publish a new npm package, [`react-lifecycles-compat`](https://github.com/reactjs/react-lifecycles-compat). This package polyfills components so that the new `getDerivedStateFromProps` and `getSnapshotBeforeUpdate` lifecycles will also work with older versions of React (0.14.9+). + +To use this polyfill, first add it as a dependency to your library: + +```bash +# Yarn +yarn add react-lifecycles-compat + +# NPM +npm install react-lifecycles-compat --save +``` + +Next, update your components to use the new lifecycles (as described above). + +Lastly, use the polyfill to make your component backwards compatible with older versions of React: +`embed:update-on-async-rendering/using-react-lifecycles-compat.js` diff --git a/content/blog/2018-03-29-react-v-16-3.md b/content/blog/2018-03-29-react-v-16-3.md new file mode 100644 index 00000000000..86b5bf2470f --- /dev/null +++ b/content/blog/2018-03-29-react-v-16-3.md @@ -0,0 +1,95 @@ +--- +title: "React v16.3.0: New lifecycles and context API" +author: [bvaughn] +--- + +A few days ago, we [wrote a post about upcoming changes to our legacy lifecycle methods](/blog/2018/03/27/update-on-async-rendering.html), including gradual migration strategies. In React 16.3.0, we are adding a few new lifecycle methods to assist with that migration. We are also introducing new APIs for long requested features: an official context API, a ref forwarding API, and an ergonomic ref API. + +Read on to learn more about the release. + +## Official Context API + +For many years, React has offered an experimental API for context. Although it was a powerful tool, its use was discouraged because of inherent problems in the API, and because we always intended to replace the experimental API with a better one. + +Version 16.3 introduces a new context API that is more efficient and supports both static type checking and deep updates. + +> **Note** +> +> The old context API will keep working for all React 16.x releases, so you will have time to migrate. + +Here is an example illustrating how you might inject a "theme" using the new context API: +`embed:16-3-release-blog-post/context-example.js` + +[Learn more about the new context API here.](/docs/context.html) + +## `createRef` API + +Previously, React provided two ways of managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recommendation was to use the callback form instead. + +Version 16.3 adds a new option for managing refs that offers the convenience of a string ref without any of the downsides: +`embed:16-3-release-blog-post/create-ref-example.js` + +> **Note:** +> +> Callback refs will continue to be supported in addition to the new `createRef` API. +> +> You don't need to replace callback refs in your components. They are slightly more flexible, so they will remain as an advanced feature. + +[Learn more about the new `createRef` API here.](/docs/refs-and-the-dom.html) + +## `forwardRef` API + +Generally, React components are declarative, but sometimes imperative access to the component instances and the underlying DOM nodes is necessary. This is common for use cases like managing focus, selection, or animations. React provides [refs](/docs/refs-and-the-dom.html) as a way to solve this problem. However, component encapsulation poses some challenges with refs. + +For example, if you replace a `