Browse Source

Merge branch 'master' into 16.3-release-blog-post

main
Brian Vaughn 7 years ago
parent
commit
b7b97c0ea4
  1. 8
      .github/PULL_REQUEST_TEMPLATE.md
  2. 193
      content/blog/2018-03-27-update-on-async-rendering.md
  3. 3
      content/community/examples.md
  4. 5
      content/community/meetups.md
  5. 1
      content/community/tools-ui-components.md
  6. 6
      content/docs/components-and-props.md
  7. 13
      content/docs/conditional-rendering.md
  8. 2
      content/docs/hello-world.md
  9. 4
      content/docs/higher-order-components.md
  10. 2
      content/docs/how-to-contribute.md
  11. 2
      content/docs/integrating-with-other-libraries.md
  12. 2
      content/docs/portals.md
  13. 2
      content/docs/reconciliation.md
  14. 2
      content/docs/reference-javascript-environment-requirements.md
  15. 2
      content/docs/render-props.md
  16. 2
      content/docs/static-type-checking.md
  17. 6
      content/home/examples/a-component-using-external-plugins.js
  18. 6
      content/home/examples/an-application.js
  19. 39
      examples/update-on-async-rendering/adding-event-listeners-after.js
  20. 26
      examples/update-on-async-rendering/adding-event-listeners-before.js
  21. 29
      examples/update-on-async-rendering/adding-event-listeners-create-subscription.js
  22. 30
      examples/update-on-async-rendering/fetching-external-data-after.js
  23. 30
      examples/update-on-async-rendering/fetching-external-data-before.js
  24. 8
      examples/update-on-async-rendering/initializing-state-after.js
  25. 12
      examples/update-on-async-rendering/initializing-state-before.js
  26. 12
      examples/update-on-async-rendering/invoking-external-callbacks-after.js
  27. 12
      examples/update-on-async-rendering/invoking-external-callbacks-before.js
  28. 19
      examples/update-on-async-rendering/new-lifecycles-overview.js
  29. 36
      examples/update-on-async-rendering/react-dom-properties-before-update-after.js
  30. 37
      examples/update-on-async-rendering/react-dom-properties-before-update-before.js
  31. 55
      examples/update-on-async-rendering/updating-external-data-when-props-change-after.js
  32. 41
      examples/update-on-async-rendering/updating-external-data-when-props-change-before.js
  33. 24
      examples/update-on-async-rendering/updating-state-from-props-after.js
  34. 16
      examples/update-on-async-rendering/updating-state-from-props-before.js
  35. 16
      examples/update-on-async-rendering/using-react-lifecycles-compat.js
  36. 8
      src/components/CodeEditor/CodeEditor.js
  37. 8
      src/components/LayoutFooter/Footer.js
  38. 178
      src/templates/components/Sidebar/Section.js

8
.github/PULL_REQUEST_TEMPLATE.md

@ -1,9 +1,13 @@
<!--
Thank you for the PR! Contributors like you keep React awesome!
Please see the Contribution Guide for guidelines:
https://github.com/reactjs/reactjs.org/blob/master/CONTRIBUTING.md
If your PR references an existing issue, please add the issue number below:
If your PR references an existing issue, please add the issue number below
#<Issue>
-->

193
content/blog/2018-03-27-update-on-async-rendering.md

@ -0,0 +1,193 @@
---
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`:
`embed:update-on-async-rendering/new-lifecycles-overview.js`
### New lifecycle: `getDerivedStateFromProps`
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`
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`.
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)
- [Updating external data when props change](#updating-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.
### 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`
> 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`
### Updating 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`

3
content/community/examples.md

@ -12,7 +12,7 @@ There are many example projects created by the React community. Feel free to add
* **[Calculator](https://github.com/ahfarmer/calculator)** Implementation of the iOS calculator built in React
* **[Emoji Search](https://github.com/ahfarmer/emoji-search)** Simple React app for searching emoji
* **[Github Battle App](https://github.com/ReactTraining/react-fundamentals/tree/hosting)** Battle two Github users and see the most popular Github projects for any language.
* **[K5 Showcase](https://showcase.cloud.global.fujitsu.com):** Sample applications for React.js and Flux.
* **[K5 Playground](https://playground.cloud.global.fujitsu.com):** Sample applications for React.js and Flux.
* **[React Powered Hacker News Client](https://github.com/insin/react-hn)** A React & react-router-powered implementation of Hacker News using its Firebase API.
* **[Pokedex](https://github.com/alik0211/pokedex)** The list of Pokémon with live search
* **[Progressive Web Tetris](https://github.com/skidding/flatris)** Besides a beautiful, mobile-friendly implementation of Tetris, this project is a playground for integrating and experimenting with web technologies.
@ -20,3 +20,4 @@ There are many example projects created by the React community. Feel free to add
* **[Hacker News Clone React/GraphQL](https://github.com/clintonwoo/hackernews-react-graphql)** Hacker News clone rewritten with universal JavaScript, using React and GraphQL.
* **[Bitcoin Price Index](https://github.com/mrkjlchvz/bitcoin-price-index)** Simple bitcoin price index data from CoinDesk API.
* **[Builder Book](https://github.com/builderbook/builderbook)** Open source web app to write and host documentation or sell books. Built with React, Material-UI, Next, Express, Mongoose, MongoDB.
* **[GFonts Space](https://github.com/pankajladhar/GFontsSpace)** A space which allows user to play with Google fonts. Built with React, Redux and React-Router.

5
content/community/meetups.md

@ -58,6 +58,8 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
## India
* [Bangalore](https://www.meetup.com/ReactJS-Bangalore/)
* [Chennai](https://www.meetup.com/React-Chennai/)
* [Gurgaon](https://www.meetup.com/React-Gurgaon/)
## Ireland
* [Dublin](http://www.meetup.com/ReactJS-Dublin/)
@ -84,6 +86,9 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
## Poland
* [Warsaw](http://www.meetup.com/React-js-Warsaw/)
## Scotland (UK)
* [Edinburgh](https://www.meetup.com/React-Scotland/)
## Spain
* [Barcelona](http://www.meetup.com/ReactJS-Barcelona/)

1
content/community/tools-ui-components.md

@ -65,6 +65,7 @@ permalink: community/ui-components.html
* **[valuelink](https://github.com/Volicon/valuelink):** Full-featured two-way data binding and forms validation with extended React links.
* **[video-react](https://github.com/video-react/video-react)**: A web video player built for the HTML5 world using React library.
* **[Winterfell](https://github.com/andrewhathaway/Winterfell):** Generate complex, validated and extendable JSON-based forms in React
* **[Mobiscroll Lite for React](https://mobiscroll.com/forms/react)** A collection of 15 free UI components ranging from inputs, selects, sliders, alerts to rating.
## Fee Based Components

6
content/docs/components-and-props.md

@ -85,11 +85,11 @@ Let's recap what happens in this example:
3. Our `Welcome` component returns a `<h1>Hello, Sara</h1>` element as the result.
4. React DOM efficiently updates the DOM to match `<h1>Hello, Sara</h1>`.
>**Caveat:**
>
>Always start component names with a capital letter.
>**Note:** Always start component names with a capital letter.
>
>React treats components starting with lowercase letters as DOM tags. For example, `<div />` represents an HTML div tag, but `<Welcome />` represents a component and requires `Welcome` to be in scope.
>
>You can read more about the reasoning behind this convention [here.](https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized)
## Composing Components

13
content/docs/conditional-rendering.md

@ -92,13 +92,12 @@ class LoginControl extends React.Component {
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
const button = isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
);
return (
<div>

2
content/docs/hello-world.md

@ -23,7 +23,7 @@ ReactDOM.render(
);
```
It renders a header saying "Hello, world!" on the page.
It renders a heading saying "Hello, world!" on the page.
The next few sections will gradually introduce you to using React. We will examine the building blocks of React apps: elements and components. Once you master them, you can create complex apps from small reusable pieces.

4
content/docs/higher-order-components.md

@ -106,7 +106,7 @@ class BlogPost extends React.Component {
- Inside the listener, call `setState` whenever the data source changes.
- On unmount, remove the change listener.
You can imagine that in a large app, this same pattern of subscribing to `DataSource` and calling `setState` will occur over and over again. We want an abstraction that allows us to define this logic in a single place and share them across many components. This is where higher-order components excel.
You can imagine that in a large app, this same pattern of subscribing to `DataSource` and calling `setState` will occur over and over again. We want an abstraction that allows us to define this logic in a single place and share it across many components. This is where higher-order components excel.
We can write a function that creates components, like `CommentList` and `BlogPost`, that subscribe to `DataSource`. The function will accept as one of its arguments a child component that receives the subscribed data as a prop. Let's call the function `withSubscription`:
@ -190,7 +190,7 @@ function logProps(InputComponent) {
const EnhancedComponent = logProps(InputComponent);
```
There are a few problems with this. One is that the input component cannot be reused separately from the enhanced component. More crucially, if you apply another HOC to `EnhancedComponent` that *also* mutates `componentWillReceiveProps`, the first HOC's functionality will be overridden! This HOC also won't work with function components, which do not have lifecycle methods.
There are a few problems with this. One is that the input component cannot be reused separately from the enhanced component. More crucially, if you apply another HOC to `EnhancedComponent` that *also* mutates `componentWillReceiveProps`, the first HOC's functionality will be overridden! This HOC also won't work with functional components, which do not have lifecycle methods.
Mutating HOCs are a leaky abstraction—the consumer must know how they are implemented in order to avoid conflicts with other HOCs.

2
content/docs/how-to-contribute.md

@ -41,7 +41,7 @@ We are using [GitHub Issues](https://github.com/facebook/react/issues) for our p
#### Reporting New Issues
The best way to get your bug fixed is to provide a reduced test case. This [JSFiddle template](https://jsfiddle.net/84v837e9/) is a great starting point.
The best way to get your bug fixed is to provide a reduced test case. This [JSFiddle template](https://jsfiddle.net/Luktwrdm/) is a great starting point.
#### Security Bugs

2
content/docs/integrating-with-other-libraries.md

@ -10,7 +10,7 @@ React can be used in any web application. It can be embedded in other applicatio
React is unaware of changes made to the DOM outside of React. It determines updates based on its own internal representation, and if the same DOM nodes are manipulated by another library, React gets confused and has no way to recover.
This does not mean it is impossible or even necessarily difficult to combine React with other ways of affecting the DOM, you just have to be mindful of what each are doing.
This does not mean it is impossible or even necessarily difficult to combine React with other ways of affecting the DOM, you just have to be mindful of what each is doing.
The easiest way to avoid conflicts is to prevent the React component from updating. You can do this by rendering elements that React has no reason to update, like an empty `<div />`.

2
content/docs/portals.md

@ -35,7 +35,7 @@ render() {
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(
this.props.children,
domNode,
domNode
);
}
```

2
content/docs/reconciliation.md

@ -140,7 +140,7 @@ When that's not the case, you can add a new ID property to your model or hash so
As a last resort, you can pass an item's index in the array as a key. This can work well if the items are never reordered, but reorders will be slow.
Reorders can also cause issues with component state when indexes are used as keys. Component instances are updated and reused based on their key. If the key is an index, moving an item changes it. As a result, component state for things like controlled inputs can get mixed up and updated in unexpected ways.
Reorders can also cause issues with component state when indexes are used as keys. Component instances are updated and reused based on their key. If the key is an index, moving an item changes it. As a result, component state for things like uncontrolled inputs can get mixed up and updated in unexpected ways.
[Here](codepen://reconciliation/index-used-as-key) is an example of the issues that can be caused by using indexes as keys on CodePen, and [here](codepen://reconciliation/no-index-used-as-key) is a updated version of the same example showing how not using indexes as keys will fix these reordering, sorting, and prepending issues.

2
content/docs/reference-javascript-environment-requirements.md

@ -6,7 +6,7 @@ category: Reference
permalink: docs/javascript-environment-requirements.html
---
React 16 depends on the collection types [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). If you support older browsers and devices which may not yet provide these natively (e.g. IE < 11), consider including a global polyfill in your bundled application, such as [core-js](https://github.com/zloirock/core-js) or [babel-polyfill](https://babeljs.io/docs/usage/polyfill/).
React 16 depends on the collection types [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). If you support older browsers and devices which may not yet provide these natively (e.g. IE < 11) or which have non-compliant implementations (e.g. IE 11), consider including a global polyfill in your bundled application, such as [core-js](https://github.com/zloirock/core-js) or [babel-polyfill](https://babeljs.io/docs/usage/polyfill/).
A polyfilled environment for React 16 using core-js to support older browsers might look like:

2
content/docs/render-props.md

@ -209,7 +209,7 @@ class MouseTracker extends React.Component {
}
```
Now, instead of effectively cloning the `<Mouse>` component and hard-coding something else in its `render` method to solve for a specific use case, we instead provide a `render` prop that `<Mouse>` can use to dynamically determine what it renders.
Now, instead of effectively cloning the `<Mouse>` component and hard-coding something else in its `render` method to solve for a specific use case, we provide a `render` prop that `<Mouse>` can use to dynamically determine what it renders.
More concretely, **a render prop is a function prop that a component uses to know what to render.**

2
content/docs/static-type-checking.md

@ -309,7 +309,7 @@ You are now ready to code! We recommend to check out the following resources to
[Reason](https://reasonml.github.io/) is not a new language; it's a new syntax and toolchain powered by the battle-tested language, [OCaml](http://ocaml.org/). Reason gives OCaml a familiar syntax geared toward JavaScript programmers, and caters to the existing NPM/Yarn workflow folks already know.
Reason is developed at Facebook, and is used in some of its products like Messenger. It is still somewhat experimental but it has [dedicated React bindings](https://reasonml.github.io/reason-react/) maintained by Facebook and a [vibrant community](https://reasonml.github.io/community/).
Reason is developed at Facebook, and is used in some of its products like Messenger. It is still somewhat experimental but it has [dedicated React bindings](https://reasonml.github.io/reason-react/) maintained by Facebook and a [vibrant community](https://reasonml.github.io/docs/en/community.html).
## Kotlin

6
content/home/examples/a-component-using-external-plugins.js

@ -2,7 +2,7 @@ class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = { value: 'Type some *markdown* here!' };
this.state = { value: 'Hello, **world**!' };
}
handleChange(e) {
@ -18,7 +18,11 @@ class MarkdownEditor extends React.Component {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<label htmlFor="markdown-content">
Enter some markdown
</label>
<textarea
id="markdown-content"
onChange={this.handleChange}
defaultValue={this.state.value}
/>

6
content/home/examples/an-application.js

@ -12,7 +12,11 @@ class TodoApp extends React.Component {
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<label htmlFor="new-todo">
What needs to be done?
</label>
<input
id="new-todo"
onChange={this.handleChange}
value={this.state.text}
/>
@ -56,4 +60,4 @@ class TodoList extends React.Component {
}
}
ReactDOM.render(<TodoApp />, mountNode);
ReactDOM.render(<TodoApp />, mountNode);

39
examples/update-on-async-rendering/adding-event-listeners-after.js

@ -0,0 +1,39 @@
// After
class ExampleComponent extends React.Component {
// highlight-range{1-3}
state = {
subscribedValue: this.props.dataSource.value,
};
// highlight-line
// highlight-range{1-18}
componentDidMount() {
// Event listeners are only safe to add after mount,
// So they won't leak if mount is interrupted or errors.
this.props.dataSource.subscribe(
this.handleSubscriptionChange
);
// External values could change between render and mount,
// In some cases it may be important to handle this case.
if (
this.state.subscribedValue !==
this.props.dataSource.value
) {
this.setState({
subscribedValue: this.props.dataSource.value,
});
}
}
componentWillUnmount() {
this.props.dataSource.unsubscribe(
this.handleSubscriptionChange
);
}
handleSubscriptionChange = dataSource => {
this.setState({
subscribedValue: dataSource.value,
});
};
}

26
examples/update-on-async-rendering/adding-event-listeners-before.js

@ -0,0 +1,26 @@
// Before
class ExampleComponent extends React.Component {
// highlight-range{1-10}
componentWillMount() {
this.setState({
subscribedValue: this.props.dataSource.value,
});
// This is not safe; it can leak!
this.props.dataSource.subscribe(
this.handleSubscriptionChange
);
}
componentWillUnmount() {
this.props.dataSource.unsubscribe(
this.handleSubscriptionChange
);
}
handleSubscriptionChange = dataSource => {
this.setState({
subscribedValue: dataSource.value,
});
};
}

29
examples/update-on-async-rendering/adding-event-listeners-create-subscription.js

@ -0,0 +1,29 @@
import {createSubscription} from 'create-subscription';
const Subscription = createSubscription({
getCurrentValue(sourceProp) {
// Return the current value of the subscription (sourceProp).
return sourceProp.value;
},
subscribe(sourceProp, callback) {
function handleSubscriptionChange() {
callback(sourceProp.value);
}
// Subscribe (e.g. add an event listener) to the subscription (sourceProp).
// Call callback(newValue) whenever a subscription changes.
sourceProp.subscribe(handleSubscriptionChange);
// Return an unsubscribe method.
return function unsubscribe() {
sourceProp.unsubscribe(handleSubscriptionChange);
};
},
});
// Rather than passing the subscribable source to our ExampleComponent,
// We could just pass the subscribed value directly:
<Subscription source={dataSource}>
{value => <ExampleComponent subscribedValue={value} />}
</Subscription>;

30
examples/update-on-async-rendering/fetching-external-data-after.js

@ -0,0 +1,30 @@
// After
class ExampleComponent extends React.Component {
state = {
externalData: null,
};
// highlight-range{1-8}
componentDidMount() {
this._asyncRequest = asyncLoadData().then(
externalData => {
this._asyncRequest = null;
this.setState({externalData});
}
);
}
componentWillUnmount() {
if (this._asyncRequest) {
this._asyncRequest.cancel();
}
}
render() {
if (this.state.externalData === null) {
// Render loading state ...
} else {
// Render real UI ...
}
}
}

30
examples/update-on-async-rendering/fetching-external-data-before.js

@ -0,0 +1,30 @@
// Before
class ExampleComponent extends React.Component {
state = {
externalData: null,
};
// highlight-range{1-8}
componentWillMount() {
this._asyncRequest = asyncLoadData().then(
externalData => {
this._asyncRequest = null;
this.setState({externalData});
}
);
}
componentWillUnmount() {
if (this._asyncRequest) {
this._asyncRequest.cancel();
}
}
render() {
if (this.state.externalData === null) {
// Render loading state ...
} else {
// Render real UI ...
}
}
}

8
examples/update-on-async-rendering/initializing-state-after.js

@ -0,0 +1,8 @@
// After
class ExampleComponent extends React.Component {
// highlight-range{1-4}
state = {
currentColor: this.props.defaultColor,
palette: 'rgb',
};
}

12
examples/update-on-async-rendering/initializing-state-before.js

@ -0,0 +1,12 @@
// Before
class ExampleComponent extends React.Component {
state = {};
// highlight-range{1-6}
componentWillMount() {
this.setState({
currentColor: this.props.defaultColor,
palette: 'rgb',
});
}
}

12
examples/update-on-async-rendering/invoking-external-callbacks-after.js

@ -0,0 +1,12 @@
// After
class ExampleComponent extends React.Component {
// highlight-range{1-8}
componentDidUpdate(prevProps, prevState) {
if (
this.state.someStatefulValue !==
prevState.someStatefulValue
) {
this.props.onChange(this.state.someStatefulValue);
}
}
}

12
examples/update-on-async-rendering/invoking-external-callbacks-before.js

@ -0,0 +1,12 @@
// Before
class ExampleComponent extends React.Component {
// highlight-range{1-8}
componentWillUpdate(nextProps, nextState) {
if (
this.state.someStatefulValue !==
nextState.someStatefulValue
) {
nextProps.onChange(nextState.someStatefulValue);
}
}
}

19
examples/update-on-async-rendering/new-lifecycles-overview.js

@ -0,0 +1,19 @@
class Example extends React.Component<
Props,
State,
Snapshot
> {
static getDerivedStateFromProps(
nextProps: Props,
prevState: State
): $Shape<State> | null {
// ...
}
getSnapshotBeforeUpdate(
prevProps: Props,
prevState: State
): Snapshot {
// ...
}
}

36
examples/update-on-async-rendering/react-dom-properties-before-update-after.js

@ -0,0 +1,36 @@
class ScrollingList extends React.Component {
listRef = null;
// highlight-range{1-8}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the current height of the list so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
return this.listRef.scrollHeight;
}
return null;
}
// highlight-range{1-8}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
this.listRef.scrollTop +=
this.listRef.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.setListRef}>
{/* ...contents... */}
</div>
);
}
setListRef = ref => {
this.listRef = ref;
};
}

37
examples/update-on-async-rendering/react-dom-properties-before-update-before.js

@ -0,0 +1,37 @@
class ScrollingList extends React.Component {
listRef = null;
previousScrollHeight = null;
// highlight-range{1-7}
componentWillUpdate(nextProps, nextState) {
// Are we adding new items to the list?
// Capture the current height of the list so we can adjust scroll later.
if (this.props.list.length < nextProps.list.length) {
this.previousScrollHeight = this.listRef.scrollHeight;
}
}
// highlight-range{1-10}
componentDidUpdate(prevProps, prevState) {
// If previousScrollHeight is set, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
if (this.previousScrollHeight !== null) {
this.listRef.scrollTop +=
this.listRef.scrollHeight -
this.previousScrollHeight;
this.previousScrollHeight = null;
}
}
render() {
return (
<div ref={this.setListRef}>
{/* ...contents... */}
</div>
);
}
setListRef = ref => {
this.listRef = ref;
};
}

55
examples/update-on-async-rendering/updating-external-data-when-props-change-after.js

@ -0,0 +1,55 @@
// After
class ExampleComponent extends React.Component {
state = {
externalData: null,
};
// highlight-range{1-13}
static getDerivedStateFromProps(nextProps, prevState) {
// Store prevId in state so we can compare when props change.
// Clear out previously-loaded data (so we don't render stale stuff).
if (nextProps.id !== prevState.prevId) {
return {
externalData: null,
prevId: nextProps.id,
};
}
// No state update necessary
return null;
}
componentDidMount() {
this._loadAsyncData();
}
// highlight-range{1-5}
componentDidUpdate(prevProps, prevState) {
if (prevState.externalData === null) {
this._loadAsyncData();
}
}
componentWillUnmount() {
if (this._asyncRequest) {
this._asyncRequest.cancel();
}
}
render() {
if (this.state.externalData === null) {
// Render loading state ...
} else {
// Render real UI ...
}
}
_loadAsyncData() {
this._asyncRequest = asyncLoadData(this.props.id).then(
externalData => {
this._asyncRequest = null;
this.setState({externalData});
}
);
}
}

41
examples/update-on-async-rendering/updating-external-data-when-props-change-before.js

@ -0,0 +1,41 @@
// Before
class ExampleComponent extends React.Component {
state = {
externalData: null,
};
componentDidMount() {
this._loadAsyncData();
}
// highlight-range{1-6}
componentWillReceiveProps(nextProps) {
if (nextProps.id !== this.props.id) {
this.setState({externalData: null});
this._loadAsyncData();
}
}
componentWillUnmount() {
if (this._asyncRequest) {
this._asyncRequest.cancel();
}
}
render() {
if (this.state.externalData === null) {
// Render loading state ...
} else {
// Render real UI ...
}
}
_loadAsyncData() {
this._asyncRequest = asyncLoadData(this.props.id).then(
externalData => {
this._asyncRequest = null;
this.setState({externalData});
}
);
}
}

24
examples/update-on-async-rendering/updating-state-from-props-after.js

@ -0,0 +1,24 @@
// After
class ExampleComponent extends React.Component {
// Initialize state in constructor,
// Or with a property initializer.
// highlight-range{1-4}
state = {
isScrollingDown: false,
lastRow: null,
};
// highlight-range{1-8}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.currentRow !== prevState.lastRow) {
return {
isScrollingDown:
nextProps.currentRow > prevState.lastRow,
lastRow: nextProps.currentRow,
};
}
// Return null to indicate no change to state.
return null;
}
}

16
examples/update-on-async-rendering/updating-state-from-props-before.js

@ -0,0 +1,16 @@
// Before
class ExampleComponent extends React.Component {
state = {
isScrollingDown: false,
};
// highlight-range{1-8}
componentWillReceiveProps(nextProps) {
if (this.props.currentRow !== nextProps.currentRow) {
this.setState({
isScrollingDown:
nextProps.currentRow > this.props.currentRow,
});
}
}
}

16
examples/update-on-async-rendering/using-react-lifecycles-compat.js

@ -0,0 +1,16 @@
import React from 'react';
// highlight-next-line
import polyfill from 'react-lifecycles-compat';
class ExampleComponent extends React.Component {
// highlight-next-line
static getDerivedStateFromProps(nextProps, prevState) {
// Your state update logic here ...
}
}
// Polyfill your component to work with older versions of React:
// highlight-next-line
polyfill(ExampleComponent);
export default ExampleComponent;

8
src/components/CodeEditor/CodeEditor.js

@ -179,7 +179,7 @@ class CodeEditor extends Component {
},
}}
className="gatsby-highlight">
<LiveEditor onChange={this._onChange} />
<LiveEditor ignoreTabKey={true} onChange={this._onChange} />
</div>
</div>
{error && (
@ -257,9 +257,13 @@ class CodeEditor extends Component {
padding: '5px 10px',
},
'& label': {
display: 'block',
marginTop: 10,
},
'& textarea': {
width: '100%',
marginTop: 10,
height: 60,
padding: 5,
},

8
src/components/LayoutFooter/Footer.js

@ -64,7 +64,9 @@ const Footer = ({layoutHasSidebar = false}: {layoutHasSidebar: boolean}) => (
{sectionListDocs.map(section => {
const defaultItem = section.items[0];
return (
<FooterLink to={`/docs/${defaultItem.id}.html`}>
<FooterLink
to={`/docs/${defaultItem.id}.html`}
key={section.title}>
{section.title}
</FooterLink>
);
@ -112,7 +114,9 @@ const Footer = ({layoutHasSidebar = false}: {layoutHasSidebar: boolean}) => (
<FooterNav layoutHasSidebar={layoutHasSidebar}>
<MetaTitle onDark={true}>Community</MetaTitle>
{sectionListCommunity.map(section => (
<FooterLink to={`/community/${section.items[0].id}.html`}>
<FooterLink
to={`/community/${section.items[0].id}.html`}
key={section.title}>
{section.title}
</FooterLink>
))}

178
src/templates/components/Sidebar/Section.js

@ -10,94 +10,104 @@ import isItemActive from 'utils/isItemActive';
import MetaTitle from '../MetaTitle';
import ChevronSvg from '../ChevronSvg';
const Section = ({
activeItemId,
createLink,
isActive,
isScrollSync,
location,
onLinkClick,
onSectionTitleClick,
section,
}) => (
<div>
<button
css={{
cursor: 'pointer',
backgroundColor: 'transparent',
border: 0,
marginTop: 10,
}}
onClick={onSectionTitleClick}>
<MetaTitle
cssProps={{
[media.greaterThan('small')]: {
color: isActive ? colors.text : colors.subtle,
':hover': {
color: colors.text,
},
},
}}>
{section.title}
<ChevronSvg
cssProps={{
marginLeft: 7,
transform: isActive ? 'rotateX(180deg)' : 'rotateX(0deg)',
transition: 'transform 0.2s ease',
[media.lessThan('small')]: {
display: 'none',
},
class Section extends React.Component {
state = {uid: ('' + Math.random()).replace(/\D/g, '')};
render() {
const {
activeItemId,
createLink,
isActive,
isScrollSync,
location,
onLinkClick,
onSectionTitleClick,
section,
} = this.props;
const uid = 'section_' + this.state.uid;
return (
<div>
<button
aria-expanded={isActive}
aria-controls={uid}
css={{
cursor: 'pointer',
backgroundColor: 'transparent',
border: 0,
marginTop: 10,
}}
/>
</MetaTitle>
</button>
<ul
css={{
marginBottom: 10,
onClick={onSectionTitleClick}>
<MetaTitle
cssProps={{
[media.greaterThan('small')]: {
color: isActive ? colors.text : colors.subtle,
':hover': {
color: colors.text,
},
},
}}>
{section.title}
<ChevronSvg
cssProps={{
marginLeft: 7,
transform: isActive ? 'rotateX(180deg)' : 'rotateX(0deg)',
transition: 'transform 0.2s ease',
[media.greaterThan('small')]: {
display: isActive ? 'block' : 'none',
},
}}>
{section.items.map(item => (
<li
key={item.id}
[media.lessThan('small')]: {
display: 'none',
},
}}
/>
</MetaTitle>
</button>
<ul
id={uid}
css={{
marginTop: 5,
marginBottom: 10,
[media.greaterThan('small')]: {
display: isActive ? 'block' : 'none',
},
}}>
{createLink({
isActive: isScrollSync
? activeItemId === item.id
: isItemActive(location, item),
item,
location,
onLinkClick,
section,
})}
{section.items.map(item => (
<li
key={item.id}
css={{
marginTop: 5,
}}>
{createLink({
isActive: isScrollSync
? activeItemId === item.id
: isItemActive(location, item),
item,
location,
onLinkClick,
section,
})}
{item.subitems && (
<ul css={{marginLeft: 20}}>
{item.subitems.map(subitem => (
<li key={subitem.id}>
{createLink({
isActive: isScrollSync
? activeItemId === subitem.id
: isItemActive(location, subitem),
item: subitem,
location,
onLinkClick,
section,
})}
</li>
))}
</ul>
)}
</li>
))}
</ul>
</div>
);
{item.subitems && (
<ul css={{marginLeft: 20}}>
{item.subitems.map(subitem => (
<li key={subitem.id}>
{createLink({
isActive: isScrollSync
? activeItemId === subitem.id
: isItemActive(location, subitem),
item: subitem,
location,
onLinkClick,
section,
})}
</li>
))}
</ul>
)}
</li>
))}
</ul>
</div>
);
}
}
export default Section;

Loading…
Cancel
Save