From 501de4a49d5ba353f6b8032aec81b3352662a78a Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 16 Nov 2022 21:35:45 +0000 Subject: [PATCH] [Beta] PureComponent API (#5271) --- beta/src/content/apis/react/PureComponent.md | 202 ++++++++++++++++++- beta/src/content/apis/react/memo.md | 6 +- beta/src/sidebarReference.json | 3 +- 3 files changed, 196 insertions(+), 15 deletions(-) diff --git a/beta/src/content/apis/react/PureComponent.md b/beta/src/content/apis/react/PureComponent.md index e1893cbe..460db89d 100644 --- a/beta/src/content/apis/react/PureComponent.md +++ b/beta/src/content/apis/react/PureComponent.md @@ -1,24 +1,21 @@ --- -title: React.PureComponent +title: PureComponent --- - + -This section is incomplete, please see the old docs for [React.PureComponent.](https://reactjs.org/docs/react-api.html#reactpurecomponent) - - +We recommend to define components as functions instead of classes. [See how to migrate.](#alternatives) + -React.PureComponent is similar to React.Component. The difference between them is that React.Component doesn’t implement shouldComponentUpdate(), but React.PureComponent implements it with a shallow prop and state comparison. - -If your React component’s render() function renders the same result given the same props and state, you can use React.PureComponent for a performance boost in some cases. +`PureComponent` is similar to [`Component`](/apis/react/Component) but it skips re-renders for same props and state. Class components are still supported by React, but we don't recommend using them in new code. ```js -class Welcome extends React.PureComponent { +class Greeting extends PureComponent { render() { - return

Hello, {this.props.name}

; + return

Hello, {this.props.name}!

; } } ``` @@ -26,3 +23,188 @@ class Welcome extends React.PureComponent {
+ +--- + +## Usage {/*usage*/} + +### Skipping unnecessary re-renders for class components {/*skipping-unnecessary-re-renders-for-class-components*/} + +React normally re-renders a component whenever its parent re-renders. As an optimization, you can create a component that React will not re-render when its parent re-renders so long as its new props and state are the same as the old props and state. [Class components](/apis/react/Component) can opt into this behavior by extending `PureComponent`: + +```js {1} +class Greeting extends PureComponent { + render() { + return

Hello, {this.props.name}!

; + } +} +``` + +A React component should always have [pure rendering logic.](/learn/keeping-components-pure) This means that it must return the same output if its props, state, and context haven't changed. By using `PureComponent`, you are telling React that your component complies with this requirement, so React doesn't need to re-render as long as its props and state haven't changed. However, your component will still re-render if a context that it's using changes. + +In this example, notice that the `Greeting` component re-renders whenever `name` is changed (because that's one of its props), but not when `address` is changed (because it's not passed to `Greeting` as a prop): + + + +```js +import { PureComponent, useState } from 'react'; + +class Greeting extends PureComponent { + render() { + console.log("Greeting was rendered at", new Date().toLocaleTimeString()); + return

Hello{this.props.name && ', '}{this.props.name}!

; + } +} + +export default function MyApp() { + const [name, setName] = useState(''); + const [address, setAddress] = useState(''); + return ( + <> + + + + + ); +} +``` + +```css +label { + display: block; + margin-bottom: 16px; +} +``` + +
+ + + +We recommend to define components as functions instead of classes. [See how to migrate.](#alternatives) + + + +--- + +## Alternatives {/*alternatives*/} + +### Migrating from a `PureComponent` class component to a function {/*migrating-from-a-purecomponent-class-component-to-a-function*/} + +We recommend to use function components instead of [class components](/apis/react/Component) in the new code. If you have some existing class components using `PureComponent`, here is how you can convert them. This is the original code: + + + +```js +import { PureComponent, useState } from 'react'; + +class Greeting extends PureComponent { + render() { + console.log("Greeting was rendered at", new Date().toLocaleTimeString()); + return

Hello{this.props.name && ', '}{this.props.name}!

; + } +} + +export default function MyApp() { + const [name, setName] = useState(''); + const [address, setAddress] = useState(''); + return ( + <> + + + + + ); +} +``` + +```css +label { + display: block; + margin-bottom: 16px; +} +``` + +
+ +When you [convert this component from a class to a function,](/apis/react/Component#alternatives) wrap it in [`memo`:](/apis/react/memo) + + + +```js +import { memo, useState } from 'react'; + +const Greeting = memo(function Greeting({ name }) { + console.log("Greeting was rendered at", new Date().toLocaleTimeString()); + return

Hello{name && ', '}{name}!

; +}); + +export default function MyApp() { + const [name, setName] = useState(''); + const [address, setAddress] = useState(''); + return ( + <> + + + + + ); +} +``` + +```css +label { + display: block; + margin-bottom: 16px; +} +``` + +
+ + + +Unlike `PureComponent`, [`memo`](/apis/react/memo) does not compare the new and the old state. In function components, calling the [`set` function](/apis/react/useState#setstate) with the same state [already prevents re-renders by default,](/apis/react/memo#updating-a-memoized-component-using-state) even without `memo`. + + + +--- + +## Reference {/*reference*/} + +### `PureComponent` {/*purecomponent*/} + +To skip re-rendering a class component for same props and state, extend `PureComponent` instead of [`Component`:](/apis/react/Component) + +```js +import { PureComponent } from 'react'; + +class Greeting extends PureComponent { + render() { + return

Hello, {this.props.name}!

; + } +} +``` + +`PureComponent` is a subclass of `Component` and supports [all the `Component` APIs.](/apis/react/Component#reference) Extending `PureComponent` is equivalent to defining a custom [`shouldComponentUpdate`](/apis/react/Component#shouldcomponentupdate) method that shallowly compares props and state. + + +[See more examples.](#usage) + + diff --git a/beta/src/content/apis/react/memo.md b/beta/src/content/apis/react/memo.md index 867af92a..8b9d46a2 100644 --- a/beta/src/content/apis/react/memo.md +++ b/beta/src/content/apis/react/memo.md @@ -39,7 +39,7 @@ In this example, notice that the `Greeting` component re-renders whenever `name` ```js -import { memo, useEffect, useState } from 'react'; +import { memo, useState } from 'react'; export default function MyApp() { const [name, setName] = useState(''); @@ -109,7 +109,7 @@ Even when a component is memoized, it will still re-render when its own state ch ```js -import { memo, useEffect, useState } from 'react'; +import { memo, useState } from 'react'; export default function MyApp() { const [name, setName] = useState(''); @@ -184,7 +184,7 @@ Even when a component is memoized, it will still re-render when a context that i ```js -import { createContext, memo, useContext, useEffect, useState } from 'react'; +import { createContext, memo, useContext, useState } from 'react'; const ThemeContext = createContext(null); diff --git a/beta/src/sidebarReference.json b/beta/src/sidebarReference.json index caf2fa6b..0965531d 100644 --- a/beta/src/sidebarReference.json +++ b/beta/src/sidebarReference.json @@ -61,8 +61,7 @@ }, { "title": "PureComponent", - "path": "/apis/react/PureComponent", - "wip": true + "path": "/apis/react/PureComponent" }, { "title": "startTransition",