Component
Component
是定义为 JavaScript 类。 类组件的 React 组件的基类。React 仍然支持这些组件,但我们不建议在新代码中使用它们。
¥Component
is the base class for the React components defined as JavaScript classes. Class components are still supported by React, but we don’t recommend using them in new code.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
- 参考
Component
context
props
state
constructor(props)
componentDidCatch(error, info)
componentDidMount()
componentDidUpdate(prevProps, prevState, snapshot?)
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
componentWillUnmount()
forceUpdate(callback?)
getSnapshotBeforeUpdate(prevProps, prevState)
render()
setState(nextState, callback?)
shouldComponentUpdate(nextProps, nextState, nextContext)
UNSAFE_componentWillMount()
UNSAFE_componentWillReceiveProps(nextProps, nextContext)
UNSAFE_componentWillUpdate(nextProps, nextState)
static contextType
static defaultProps
static getDerivedStateFromError(error)
static getDerivedStateFromProps(props, state)
- 用法
- 备选方案
参考
¥Reference
Component
要将 React 组件定义为类,请扩展内置的 Component
类并定义一个 render
方法:。
¥To define a React component as a class, extend the built-in Component
class and define a render
method:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
只有 render
方法是必需的,其他方法是可选的。
¥Only the render
method is required, other methods are optional.
context
类组件的 上下文 可以用作 this.context
。只有使用 static contextType
指定要接收哪个上下文时,它才可用。
¥The context of a class component is available as this.context
. It is only available if you specify which context you want to receive using static contextType
.
类组件一次只能读取一个上下文。
¥A class component can only read one context at a time.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}
props
传递给类组件的属性可用作 this.props
。
¥The props passed to a class component are available as this.props
.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
<Greeting name="Taylor" />
state
类组件的状态可用作 this.state
。state
字段必须是一个对象。请勿直接修改状态。如果你希望更改状态,请使用新状态调用 setState
。
¥The state of a class component is available as this.state
. The state
field must be an object. Do not mutate the state directly. If you wish to change the state, call setState
with the new state.
class Counter extends Component {
state = {
age: 42,
};
handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};
render() {
return (
<>
<button onClick={this.handleAgeChange}>
Increment age
</button>
<p>You are {this.state.age}.</p>
</>
);
}
}
constructor(props)
构造函数 会在类组件挂载(添加到屏幕)之前运行。通常,构造函数在 React 中仅用于两种用途。它允许你将状态和 bind 类方法声明为类实例:
¥The constructor runs before your class component mounts (gets added to the screen). Typically, a constructor is only used for two purposes in React. It lets you declare state and bind your class methods to the class instance:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// ...
}
如果你使用现代 JavaScript 语法,则很少需要构造函数。你可以使用 公共类字段语法 重写上面的代码,现代浏览器和 Babel: 等工具都支持 公共类字段语法。
¥If you use modern JavaScript syntax, constructors are rarely needed. Instead, you can rewrite this code above using the public class field syntax which is supported both by modern browsers and tools like Babel:
class Counter extends Component {
state = { counter: 0 };
handleClick = () => {
// ...
}
构造函数不应包含任何副作用或订阅。
¥A constructor should not contain any side effects or subscriptions.
参数
¥Parameters
-
props
:组件的初始属性。¥
props
: The component’s initial props.
返回
¥Returns
constructor
不应返回任何内容。
¥constructor
should not return anything.
注意事项
¥Caveats
-
请勿在构造函数中运行任何副作用或订阅。请使用
componentDidMount
来实现。¥Do not run any side effects or subscriptions in the constructor. Instead, use
componentDidMount
for that. -
在构造函数中,你需要在任何其他语句之前调用
super(props)
。如果不这样做,构造函数运行时this.props
将变为undefined
,这可能会造成混淆并导致错误。¥Inside a constructor, you need to call
super(props)
before any other statement. If you don’t do that,this.props
will beundefined
while the constructor runs, which can be confusing and cause bugs. -
构造函数是唯一可以直接赋值
this.state
的地方。在所有其他方法中,你需要使用this.setState()
。请勿在构造函数中调用setState
。¥Constructor is the only place where you can assign
this.state
directly. In all other methods, you need to usethis.setState()
instead. Do not callsetState
in the constructor. -
使用 服务器渲染, 时,构造函数也会在服务器上运行,然后是
render
方法。但是,像componentDidMount
或componentWillUnmount
这样的生命周期方法将不会在服务器上运行。¥When you use server rendering, the constructor will run on the server too, followed by the
render
method. However, lifecycle methods likecomponentDidMount
orcomponentWillUnmount
will not run on the server. -
当 严格模式 启用时,React 将在开发环境中调用
constructor
两次,然后丢弃其中一个实例。这可以帮助你注意到需要从constructor
中移出的意外副作用。¥When Strict Mode is on, React will call
constructor
twice in development and then throw away one of the instances. This helps you notice the accidental side effects that need to be moved out of theconstructor
.
componentDidCatch(error, info)
如果定义了 componentDidCatch
,React 会在某个子组件(包括远端子组件)渲染过程中抛出错误时调用它。这可以将错误记录到生产环境中的错误报告服务中。
¥If you define componentDidCatch
, React will call it when some child component (including distant children) throws an error during rendering. This lets you log that error to an error reporting service in production.
通常,它与 static getDerivedStateFromError
一起使用,后者允许你在发生错误时更新状态并向用户显示错误消息。具有这些方法的组件称为错误边界。
¥Typically, it is used together with static getDerivedStateFromError
which lets you update state in response to an error and display an error message to the user. A component with these methods is called an error boundary.
参数
¥Parameters
-
error
:抛出的错误。实际上,它通常是Error
的一个实例,但这并不能保证,因为 JavaScript 允许对任何值进行throw
操作,包括字符串甚至null
。¥
error
: The error that was thrown. In practice, it will usually be an instance ofError
but this is not guaranteed because JavaScript allows tothrow
any value, including strings or evennull
. -
info
:一个包含有关错误的附加信息的对象。它的componentStack
字段包含抛出异常的组件的堆栈跟踪,以及其所有父组件的名称和源位置。在生产环境中,组件名称将被压缩。如果你设置了生产环境错误报告,则可以使用源映射解码组件堆栈,就像解码常规 JavaScript 错误堆栈一样。¥
info
: An object containing additional information about the error. ItscomponentStack
field contains a stack trace with the component that threw, as well as the names and source locations of all its parent components. In production, the component names will be minified. If you set up production error reporting, you can decode the component stack using sourcemaps the same way as you would do for regular JavaScript error stacks.
返回
¥Returns
componentDidCatch
不应返回任何内容。
¥componentDidCatch
should not return anything.
注意事项
¥Caveats
-
过去,通常在
componentDidCatch
内部调用setState
来更新 UI 并显示回退错误消息。此方法已弃用,建议使用static getDerivedStateFromError
。 定义。¥In the past, it was common to call
setState
insidecomponentDidCatch
in order to update the UI and display the fallback error message. This is deprecated in favor of definingstatic getDerivedStateFromError
. -
React 的生产版本和开发版本在
componentDidCatch
处理错误的方式上略有不同。在开发环境中,错误会向上冒泡到window
,这意味着任何window.onerror
或window.addEventListener('error', callback)
都会拦截已被componentDidCatch
捕获的错误。在生产环境中,错误不会冒泡,这意味着任何祖级错误处理程序只会接收未被componentDidCatch
明确捕获的错误。¥Production and development builds of React slightly differ in the way
componentDidCatch
handles errors. In development, the errors will bubble up towindow
, which means that anywindow.onerror
orwindow.addEventListener('error', callback)
will intercept the errors that have been caught bycomponentDidCatch
. In production, instead, the errors will not bubble up, which means any ancestor error handler will only receive errors not explicitly caught bycomponentDidCatch
.
componentDidMount()
如果定义了 componentDidMount
方法,React 会在组件添加(挂载)到屏幕时调用它。这里是启动数据获取、设置订阅或操作 DOM 节点的常用位置。
¥If you define the componentDidMount
method, React will call it when your component is added (mounted) to the screen. This is a common place to start data fetching, set up subscriptions, or manipulate the DOM nodes.
如果你实现了 componentDidMount
,通常需要实现其他生命周期方法来避免错误。例如,如果 componentDidMount
读取某些状态或属性,你还必须实现 componentDidUpdate
来处理它们的更改,并实现 componentWillUnmount
来清理 componentDidMount
正在执行的操作。
¥If you implement componentDidMount
, you usually need to implement other lifecycle methods to avoid bugs. For example, if componentDidMount
reads some state or props, you also have to implement componentDidUpdate
to handle their changes, and componentWillUnmount
to clean up whatever componentDidMount
was doing.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}
参数
¥Parameters
componentDidMount
没有参数。
¥componentDidMount
does not take any parameters.
返回
¥Returns
componentDidMount
不应返回任何内容。
¥componentDidMount
should not return anything.
注意事项
¥Caveats
-
当 严格模式 启用时,在开发环境中,React 将调用
componentDidMount
,然后立即调用componentWillUnmount
,,然后再次调用componentDidMount
。这可以帮助你注意到是否忘记实现componentWillUnmount
,或者它的逻辑是否没有完全实现componentDidMount
的功能。¥When Strict Mode is on, in development React will call
componentDidMount
, then immediately callcomponentWillUnmount
, and then callcomponentDidMount
again. This helps you notice if you forgot to implementcomponentWillUnmount
or if its logic doesn’t fully “mirror” whatcomponentDidMount
does. -
虽然你可以在
componentDidMount
中立即调用setState
,但最好尽可能避免这样做。此方法将触发额外渲染,但会在浏览器更新屏幕之前发生。这保证了即使在这种情况下render
会被调用两次,用户也不会看到中间状态。请谨慎使用此模式,因为它经常会导致性能问题。在大多数情况下,你应该能够在constructor
中分配初始状态。但是,在模态窗口和工具提示等情况下,当你需要在渲染依赖于其大小或位置的内容之前测量 DOM 节点时,它可能是必不可少的。¥Although you may call
setState
immediately incomponentDidMount
, it’s best to avoid that when you can. It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though therender
will be called twice in this case, the user won’t see the intermediate state. Use this pattern with caution because it often causes performance issues. In most cases, you should be able to assign the initial state in theconstructor
instead. It can, however, be necessary for cases like modals and tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
componentDidUpdate(prevProps, prevState, snapshot?)
如果定义了 componentDidUpdate
方法,React 会在组件使用更新的属性或状态重新渲染后立即调用它。此方法不会在初始渲染时调用。
¥If you define the componentDidUpdate
method, React will call it immediately after your component has been re-rendered with updated props or state. This method is not called for the initial render.
你可以使用它在更新后操作 DOM。这里也是执行网络请求的常用位置,只要你将当前属性与之前的属性进行比较即可(例如,如果属性没有改变,则可能不需要网络请求)。通常,你会将它与 componentDidMount
和 componentWillUnmount
: 一起使用。
¥You can use it to manipulate the DOM after an update. This is also a common place to do network requests as long as you compare the current props to previous props (e.g. a network request may not be necessary if the props have not changed). Typically, you’d use it together with componentDidMount
and componentWillUnmount
:
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}
参数
¥Parameters
-
prevProps
:更新前的属性。比较prevProps
和this.props
以确定发生了什么变化。¥
prevProps
: Props before the update. CompareprevProps
tothis.props
to determine what changed. -
prevState
:更新前的状态。比较prevState
和this.state
以确定发生了什么变化。¥
prevState
: State before the update. CompareprevState
tothis.state
to determine what changed. -
snapshot
:如果你实现了getSnapshotBeforeUpdate
,snapshot
将包含你从该方法返回的值。否则,返回的是undefined
。¥
snapshot
: If you implementedgetSnapshotBeforeUpdate
,snapshot
will contain the value you returned from that method. Otherwise, it will beundefined
.
返回
¥Returns
componentDidUpdate
不应返回任何内容。
¥componentDidUpdate
should not return anything.
注意事项
¥Caveats
-
如果
shouldComponentUpdate
已定义并返回false
,则componentDidUpdate
将不会被调用。¥
componentDidUpdate
will not get called ifshouldComponentUpdate
is defined and returnsfalse
. -
componentDidUpdate
中的逻辑通常应该包含在比较this.props
与prevProps
以及this.state
与prevState
的条件语句中。否则,存在创建无限循环的风险。¥The logic inside
componentDidUpdate
should usually be wrapped in conditions comparingthis.props
withprevProps
, andthis.state
withprevState
. Otherwise, there’s a risk of creating infinite loops. -
虽然你可以在
componentDidUpdate
中立即调用setState
,但最好尽可能避免这样做。此方法将触发额外渲染,但会在浏览器更新屏幕之前发生。这保证了即使在这种情况下render
会被调用两次,用户也不会看到中间状态。此模式通常会导致性能问题,但在极少数情况下,例如模态窗口和工具提示,当你需要在渲染依赖于其大小或位置的内容之前测量 DOM 节点时,它可能是必不可少的。¥Although you may call
setState
immediately incomponentDidUpdate
, it’s best to avoid that when you can. It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though therender
will be called twice in this case, the user won’t see the intermediate state. This pattern often causes performance issues, but it may be necessary for rare cases like modals and tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
componentWillUnmount()
如果定义了 componentWillUnmount
方法,React 会在组件从屏幕移除(卸载)之前调用它。这里是取消数据获取或移除订阅的常用位置。
¥If you define the componentWillUnmount
method, React will call it before your component is removed (unmounted) from the screen. This is a common place to cancel data fetching or remove subscriptions.
componentWillUnmount
中的逻辑应该 “mirror” componentDidMount
。 中的逻辑。例如,如果 componentDidMount
设置了一个订阅,componentWillUnmount
应该清理该订阅。如果 componentWillUnmount
中的清理逻辑读取了某些属性或 state,通常还需要实现 componentDidUpdate
来清理与旧属性和状态对应的资源(例如订阅)。
¥The logic inside componentWillUnmount
should “mirror” the logic inside componentDidMount
. For example, if componentDidMount
sets up a subscription, componentWillUnmount
should clean up that subscription. If the cleanup logic in your componentWillUnmount
reads some props or state, you will usually also need to implement componentDidUpdate
to clean up resources (such as subscriptions) corresponding to the old props and state.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}
参数
¥Parameters
componentWillUnmount
没有参数。
¥componentWillUnmount
does not take any parameters.
返回
¥Returns
componentWillUnmount
不应返回任何内容。
¥componentWillUnmount
should not return anything.
注意事项
¥Caveats
-
当 严格模式 启用时,在开发环境中,React 将调用
componentDidMount
,,然后立即调用componentWillUnmount
,然后再次调用componentDidMount
。这可以帮助你注意到是否忘记实现componentWillUnmount
,或者它的逻辑是否没有完全实现componentDidMount
的功能。¥When Strict Mode is on, in development React will call
componentDidMount
, then immediately callcomponentWillUnmount
, and then callcomponentDidMount
again. This helps you notice if you forgot to implementcomponentWillUnmount
or if its logic doesn’t fully “mirror” whatcomponentDidMount
does.
forceUpdate(callback?)
强制组件重新渲染。
¥Forces a component to re-render.
通常,这不是必需的。如果你组件的 render
方法仅从 this.props
、this.state
或 this.context
, 读取数据,则当你在组件或其父组件之一内调用 setState
时,它将自动重新渲染。但是,如果组件的 render
方法直接从外部数据源读取,则必须告诉 React 在该数据源更改时更新用户界面。这就是 forceUpdate
可以实现的功能。
¥Usually, this is not necessary. If your component’s render
method only reads from this.props
, this.state
, or this.context
, it will re-render automatically when you call setState
inside your component or one of its parents. However, if your component’s render
method reads directly from an external data source, you have to tell React to update the user interface when that data source changes. That’s what forceUpdate
lets you do.
尽量避免使用 forceUpdate
,在 render
中仅从 this.props
和 this.state
读取。
¥Try to avoid all uses of forceUpdate
and only read from this.props
and this.state
in render
.
参数
¥Parameters
-
可选
callback
如果指定,React 将在更新提交后调用你提供的callback
。¥optional
callback
If specified, React will call thecallback
you’ve provided after the update is committed.
返回
¥Returns
forceUpdate
不返回任何东西。
¥forceUpdate
does not return anything.
注意事项
¥Caveats
-
如果调用
forceUpdate
,React 将重新渲染而不调用shouldComponentUpdate
。。¥If you call
forceUpdate
, React will re-render without callingshouldComponentUpdate
.
getSnapshotBeforeUpdate(prevProps, prevState)
如果你实现 getSnapshotBeforeUpdate
,React 会在更新 DOM 之前立即调用它。它使你的组件能够在 DOM 可能发生变化之前捕获一些信息(例如滚动位置)。此生命周期方法返回的任何值都将作为参数传递给 componentDidUpdate
。。
¥If you implement getSnapshotBeforeUpdate
, React will call it immediately before React updates the DOM. It enables your component to capture some information from the DOM (e.g. scroll position) before it is potentially changed. Any value returned by this lifecycle method will be passed as a parameter to componentDidUpdate
.
例如,你可以在聊天线程等需要在更新期间保持滚动位置的 UI 中使用它:
¥For example, you can use it in a UI like a chat thread that needs to preserve its scroll position during updates:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
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) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
在上面的例子中,在 getSnapshotBeforeUpdate
中直接读取 scrollHeight
属性非常重要。在 render
、UNSAFE_componentWillReceiveProps
或 UNSAFE_componentWillUpdate
中读取它是不安全的,因为这些方法的调用和 React 更新 DOM 之间存在潜在的时间差。
¥In the above example, it is important to read the scrollHeight
property directly in getSnapshotBeforeUpdate
. It is not safe to read it in render
, UNSAFE_componentWillReceiveProps
, or UNSAFE_componentWillUpdate
because there is a potential time gap between these methods getting called and React updating the DOM.
参数
¥Parameters
-
prevProps
:更新前的属性。比较prevProps
和this.props
以确定发生了什么变化。¥
prevProps
: Props before the update. CompareprevProps
tothis.props
to determine what changed. -
prevState
:更新前的状态。比较prevState
和this.state
以确定发生了什么变化。¥
prevState
: State before the update. CompareprevState
tothis.state
to determine what changed.
返回
¥Returns
你应该返回任意类型的快照值,或者直接返回 null
。你返回的值将作为第三个参数传递给 componentDidUpdate
。
¥You should return a snapshot value of any type that you’d like, or null
. The value you returned will be passed as the third argument to componentDidUpdate
.
注意事项
¥Caveats
-
如果
shouldComponentUpdate
已定义并返回false
,则getSnapshotBeforeUpdate
将不会被调用。¥
getSnapshotBeforeUpdate
will not get called ifshouldComponentUpdate
is defined and returnsfalse
.
render()
render
方法是类组件中唯一必需的方法。
¥The render
method is the only required method in a class component.
render
方法应该指定你希望在屏幕上显示的内容,例如:
¥The render
method should specify what you want to appear on the screen, for example:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
React 可能随时调用 render
,因此你不应假设它在特定时间运行。通常,render
方法应该返回一段 JSX,但也支持一些 其他返回类型(例如字符串)。要计算返回的 JSX,render
方法可以读取 this.props
、this.state
和 this.context
。
¥React may call render
at any moment, so you shouldn’t assume that it runs at a particular time. Usually, the render
method should return a piece of JSX, but a few other return types (like strings) are supported. To calculate the returned JSX, the render
method can read this.props
, this.state
, and this.context
.
你应该将 render
方法编写为纯函数,这意味着如果属性、state 和 context 相同,它应该返回相同的结果。它也不应该包含副作用(例如设置订阅)或与浏览器 API 交互。副作用应该发生在事件处理程序或类似 componentDidMount
。 的方法中。
¥You should write the render
method as a pure function, meaning that it should return the same result if props, state, and context are the same. It also shouldn’t contain side effects (like setting up subscriptions) or interact with the browser APIs. Side effects should happen either in event handlers or methods like componentDidMount
.
参数
¥Parameters
render
没有参数。
¥render
does not take any parameters.
返回
¥Returns
render
可以返回任何有效的 React 节点。这包括 React 元素,例如 <div />
、字符串、数字、portals、空节点(null
、undefined
、true
和 false
)以及 React 节点数组。
¥render
can return any valid React node. This includes React elements such as <div />
, strings, numbers, portals, empty nodes (null
, undefined
, true
, and false
), and arrays of React nodes.
注意事项
¥Caveats
-
render
应该写成一个由属性、state 和 context 组成的纯函数。此方法不应产生副作用。¥
render
should be written as a pure function of props, state, and context. It should not have side effects. -
如果
shouldComponentUpdate
已定义并返回false
,则render
将不会被调用。¥
render
will not get called ifshouldComponentUpdate
is defined and returnsfalse
. -
当 严格模式 启用时,React 将在开发环境中调用
render
两次,然后丢弃其中一个结果。这可以帮助你注意到需要从render
方法中移出的意外副作用。¥When Strict Mode is on, React will call
render
twice in development and then throw away one of the results. This helps you notice the accidental side effects that need to be moved out of therender
method. -
render
调用与后续componentDidMount
或componentDidUpdate
调用之间没有一一对应的关系。某些render
调用结果可能会被 React 丢弃,以达到更好的效果。¥There is no one-to-one correspondence between the
render
call and the subsequentcomponentDidMount
orcomponentDidUpdate
call. Some of therender
call results may be discarded by React when it’s beneficial.
setState(nextState, callback?)
调用 setState
来更新 React 组件的状态。
¥Call setState
to update the state of your React component.
class Form extends Component {
state = {
name: 'Taylor',
};
handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}
render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Hello, {this.state.name}.</p>
</>
);
}
}
setState
将组件状态的更改加入队列。此方法告诉 React,此组件及其子组件需要使用新状态重新渲染。这是你更新用户界面以响应交互的主要方式。
¥setState
enqueues changes to the component state. It tells React that this component and its children need to re-render with the new state. This is the main way you’ll update the user interface in response to interactions.
你还可以将函数传递给 setState
。它允许你根据先前的状态更新状态:
¥You can also pass a function to setState
. It lets you update state based on the previous state:
handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}
你不必这样做,但如果你想在同一事件期间多次更新状态,这样做会很方便。
¥You don’t have to do this, but it’s handy if you want to update state multiple times during the same event.
参数
¥Parameters
-
nextState
:对象或函数。¥
nextState
: Either an object or a function.-
如果你将对象作为
nextState
传递,它将被浅合并到this.state
中。¥If you pass an object as
nextState
, it will be shallowly merged intothis.state
. -
如果你将函数作为
nextState
传递,它将被视为更新函数。它必须是纯函数,应将待处理状态和属性作为参数,并返回要浅合并到this.state
中的对象。React 会将你的更新程序函数放入队列中并重新渲染你的组件。在下一次渲染期间,React 将通过将所有排队的更新器应用于前一个状态来计算下一个状态。¥If you pass a function as
nextState
, it will be treated as an updater function. It must be pure, should take the pending state and props as arguments, and should return the object to be shallowly merged intothis.state
. React will put your updater function in a queue and re-render your component. During the next render, React will calculate the next state by applying all of the queued updaters to the previous state.
-
-
可选
callback
:如果指定了,React 将在更新提交后调用你提供的callback
。¥optional
callback
: If specified, React will call thecallback
you’ve provided after the update is committed.
返回
¥Returns
setState
不返回任何东西。
¥setState
does not return anything.
注意事项
¥Caveats
-
请将
setState
视为一个请求,而不是一个立即更新组件的命令。当多个组件响应某个事件更新其状态时,React 会批量更新它们,并在事件结束时一次性重新渲染它们。在极少数情况下,你需要强制同步应用特定状态更新,你可以将其封装在flushSync
, 中,但这可能会影响性能。¥Think of
setState
as a request rather than an immediate command to update the component. When multiple components update their state in response to an event, React will batch their updates and re-render them together in a single pass at the end of the event. In the rare case that you need to force a particular state update to be applied synchronously, you may wrap it influshSync
, but this may hurt performance. -
setState
不会立即更新this.state
。这使得在调用setState
之后立即读取this.state
成为一个潜在的陷阱。请使用componentDidUpdate
或 setStatecallback
参数,这两个参数都保证在应用更新后触发。如果你需要根据先前的状态设置状态,你可以像上面描述的那样将函数传递给nextState
。¥
setState
does not updatethis.state
immediately. This makes readingthis.state
right after callingsetState
a potential pitfall. Instead, usecomponentDidUpdate
or the setStatecallback
argument, either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, you can pass a function tonextState
as described above.
shouldComponentUpdate(nextProps, nextState, nextContext)
如果定义了 shouldComponentUpdate
,React 将在确定是否可以跳过重新渲染之前调用它。
¥If you define shouldComponentUpdate
, React will call it to determine whether a re-render can be skipped.
如果你确定要手写,可以比较 this.props
与 nextProps
以及 this.state
与 nextState
,然后返回 false
来告知 React 可以跳过更新。
¥If you are confident you want to write it by hand, you may compare this.props
with nextProps
and this.state
with nextState
and return false
to tell React the update can be skipped.
class Rectangle extends Component {
state = {
isHovered: false
};
shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// Nothing has changed, so a re-render is unnecessary
return false;
}
return true;
}
// ...
}
当接收到新的属性或状态时,React 会在渲染之前调用 shouldComponentUpdate
。默认为 true
。此方法不会在初始渲染或使用 forceUpdate
时调用。
¥React calls shouldComponentUpdate
before rendering when new props or state are being received. Defaults to true
. This method is not called for the initial render or when forceUpdate
is used.
参数
¥Parameters
-
nextProps
:组件即将渲染的下一个属性。比较nextProps
和this.props
以确定发生了什么变化。¥
nextProps
: The next props that the component is about to render with. ComparenextProps
tothis.props
to determine what changed. -
nextState
:组件即将渲染的下一个 state。比较nextState
和this.state
以确定发生了什么变化。¥
nextState
: The next state that the component is about to render with. ComparenextState
tothis.state
to determine what changed. -
nextContext
:组件即将渲染的下一个上下文。比较nextContext
和this.context
以确定发生了什么变化。仅在指定static contextType
时可用。¥
nextContext
: The next context that the component is about to render with. ComparenextContext
tothis.context
to determine what changed. Only available if you specifystatic contextType
.
返回
¥Returns
如果你希望组件重新渲染,请返回 true
。这是默认行为。
¥Return true
if you want the component to re-render. That’s the default behavior.
返回 false
以告知 React 可以跳过重新渲染。
¥Return false
to tell React that re-rendering can be skipped.
注意事项
¥Caveats
-
此方法仅用于性能优化。如果你的组件在没有它的情况下崩溃,请先修复该逻辑。
¥This method only exists as a performance optimization. If your component breaks without it, fix that first.
-
考虑使用
PureComponent
,而不是手动编写shouldComponentUpdate
。PureComponent
会浅层比较属性和 state,从而降低跳过必要更新的可能性。¥Consider using
PureComponent
instead of writingshouldComponentUpdate
by hand.PureComponent
shallowly compares props and state, and reduces the chance that you’ll skip a necessary update. -
我们不建议进行深度相等性检查或在
shouldComponentUpdate
中使用JSON.stringify
。它使性能变得不可预测,并且依赖于每个属性和状态的数据结构。在最好的情况下,你的应用可能会出现数秒的卡顿,而在最坏的情况下,你可能会崩溃。¥We do not recommend doing deep equality checks or using
JSON.stringify
inshouldComponentUpdate
. It makes performance unpredictable and dependent on the data structure of every prop and state. In the best case, you risk introducing multi-second stalls to your application, and in the worst case you risk crashing it. -
返回
false
并不能阻止子组件在其状态发生变化时重新渲染。¥Returning
false
does not prevent child components from re-rendering when their state changes. -
返回
false
并不能保证组件不会重新渲染。React 会使用返回值作为提示,但如果出于其他原因有必要,它仍可能选择重新渲染组件。¥Returning
false
does not guarantee that the component will not re-render. React will use the return value as a hint but it may still choose to re-render your component if it makes sense to do for other reasons.
UNSAFE_componentWillMount()
如果定义了 UNSAFE_componentWillMount
,React 将在 constructor
。 之后立即调用它。它仅出于历史原因而存在,不应在任何新代码中使用。请使用以下替代方案之一:
¥If you define UNSAFE_componentWillMount
, React will call it immediately after the constructor
. It only exists for historical reasons and should not be used in any new code. Instead, use one of the alternatives:
-
要初始化状态,请将
state
声明为类字段或在constructor
。 中设置this.state
。¥To initialize state, declare
state
as a class field or setthis.state
inside theconstructor
. -
如果你需要运行副作用或设置订阅,请将该逻辑移至
componentDidMount
。¥If you need to run a side effect or set up a subscription, move that logic to
componentDidMount
instead.
¥See examples of migrating away from unsafe lifecycles.
参数
¥Parameters
UNSAFE_componentWillMount
没有参数。
¥UNSAFE_componentWillMount
does not take any parameters.
返回
¥Returns
UNSAFE_componentWillMount
不应返回任何内容。
¥UNSAFE_componentWillMount
should not return anything.
注意事项
¥Caveats
-
如果组件实现了
static getDerivedStateFromProps
或getSnapshotBeforeUpdate
。,则UNSAFE_componentWillMount
将不会被调用。¥
UNSAFE_componentWillMount
will not get called if the component implementsstatic getDerivedStateFromProps
orgetSnapshotBeforeUpdate
. -
尽管
UNSAFE_componentWillMount
如此命名,但如果你的应用使用了诸如Suspense
。 之类的现代 React 功能,它并不保证组件一定会被挂载。如果渲染尝试被暂停(例如,因为某些子组件的代码尚未加载),React 将丢弃正在进行的树,并在下一次尝试中尝试从头开始构建组件。这就是为什么这个方法是 “unsafe”。依赖于挂载的代码(例如添加订阅)应放入componentDidMount
。。¥Despite its naming,
UNSAFE_componentWillMount
does not guarantee that the component will get mounted if your app uses modern React features likeSuspense
. If a render attempt is suspended (for example, because the code for some child component has not loaded yet), React will throw the in-progress tree away and attempt to construct the component from scratch during the next attempt. This is why this method is “unsafe”. Code that relies on mounting (like adding a subscription) should go intocomponentDidMount
. -
UNSAFE_componentWillMount
是唯一在 服务器渲染。 期间运行的生命周期方法。出于所有实际目的,它与constructor
, 完全相同,因此你应该使用constructor
来实现这种类型的逻辑。¥
UNSAFE_componentWillMount
is the only lifecycle method that runs during server rendering. For all practical purposes, it is identical toconstructor
, so you should use theconstructor
for this type of logic instead.
UNSAFE_componentWillReceiveProps(nextProps, nextContext)
如果定义了 UNSAFE_componentWillReceiveProps
,React 会在组件接收到新的属性时调用它。此方法仅因历史原因而存在,不应在任何新代码中使用。请使用以下替代方案之一:
¥If you define UNSAFE_componentWillReceiveProps
, React will call it when the component receives new props. It only exists for historical reasons and should not be used in any new code. Instead, use one of the alternatives:
-
如果你需要执行副作用(例如,获取数据、运行动画或重新初始化订阅)以响应属性的更改,请将该逻辑移至
componentDidUpdate
。¥If you need to run a side effect (for example, fetch data, run an animation, or reinitialize a subscription) in response to prop changes, move that logic to
componentDidUpdate
instead. -
如果你需要避免仅在属性更改时重新计算某些数据,请改用 记忆助手。
¥If you need to avoid re-computing some data only when a prop changes, use a memoization helper instead.
-
如果你需要在属性更改时 “reset” 某些状态,请考虑将组件设计为 完全受控 或 使用键完全不受控。
¥If you need to “reset” some state when a prop changes, consider either making a component fully controlled or fully uncontrolled with a key instead.
-
如果你需要在属性更改时 “调整” 某些状态,请检查你是否可以在渲染过程中仅根据属性计算所有必要的信息。如果无法做到,请改用
static getDerivedStateFromProps
。¥If you need to “adjust” some state when a prop changes, check whether you can compute all the necessary information from props alone during rendering. If you can’t, use
static getDerivedStateFromProps
instead.
¥See examples of migrating away from unsafe lifecycles.
参数
¥Parameters
-
nextProps
:组件即将从其父组件接收的下一个属性。比较nextProps
和this.props
以确定发生了什么变化。¥
nextProps
: The next props that the component is about to receive from its parent component. ComparenextProps
tothis.props
to determine what changed. -
nextContext
:组件即将从最近的提供程序接收的下一个上下文。比较nextContext
和this.context
以确定发生了什么变化。仅在指定static contextType
时可用。¥
nextContext
: The next context that the component is about to receive from the closest provider. ComparenextContext
tothis.context
to determine what changed. Only available if you specifystatic contextType
.
返回
¥Returns
UNSAFE_componentWillReceiveProps
不应返回任何内容。
¥UNSAFE_componentWillReceiveProps
should not return anything.
注意事项
¥Caveats
-
如果组件实现了
static getDerivedStateFromProps
或getSnapshotBeforeUpdate
。,则UNSAFE_componentWillReceiveProps
将不会被调用。¥
UNSAFE_componentWillReceiveProps
will not get called if the component implementsstatic getDerivedStateFromProps
orgetSnapshotBeforeUpdate
. -
尽管
UNSAFE_componentWillReceiveProps
如此命名,但如果你的应用使用了诸如Suspense
。 之类的现代 React 功能,它并不保证组件一定会收到这些属性。如果渲染尝试被暂停(例如,因为某些子组件的代码尚未加载),React 将丢弃正在进行的树,并在下一次尝试中尝试从头开始构建组件。下次尝试渲染时,props 可能会有所不同。这就是为什么这个方法是 “unsafe”。仅应在已提交更新时运行的代码(例如重置订阅)应放入componentDidUpdate
。。¥Despite its naming,
UNSAFE_componentWillReceiveProps
does not guarantee that the component will receive those props if your app uses modern React features likeSuspense
. If a render attempt is suspended (for example, because the code for some child component has not loaded yet), React will throw the in-progress tree away and attempt to construct the component from scratch during the next attempt. By the time of the next render attempt, the props might be different. This is why this method is “unsafe”. Code that should run only for committed updates (like resetting a subscription) should go intocomponentDidUpdate
. -
UNSAFE_componentWillReceiveProps
并不意味着组件接收到的属性与上次不同。你需要自行比较nextProps
和this.props
以检查是否有任何变化。¥
UNSAFE_componentWillReceiveProps
does not mean that the component has received different props than the last time. You need to comparenextProps
andthis.props
yourself to check if something changed. -
React 在挂载期间不会使用初始属性调用
UNSAFE_componentWillReceiveProps
。仅当组件的某些属性需要更新时才会调用此方法。例如,在同一组件中调用setState
通常不会触发UNSAFE_componentWillReceiveProps
。¥React doesn’t call
UNSAFE_componentWillReceiveProps
with initial props during mounting. It only calls this method if some of component’s props are going to be updated. For example, callingsetState
doesn’t generally triggerUNSAFE_componentWillReceiveProps
inside the same component.
UNSAFE_componentWillUpdate(nextProps, nextState)
如果定义了 UNSAFE_componentWillUpdate
,React 将在使用新的属性或状态渲染之前调用它。此方法仅因历史原因而存在,不应在任何新代码中使用。请使用以下替代方案之一:
¥If you define UNSAFE_componentWillUpdate
, React will call it before rendering with the new props or state. It only exists for historical reasons and should not be used in any new code. Instead, use one of the alternatives:
-
如果你需要运行副作用(例如,获取数据、运行动画或重新初始化订阅)来响应属性或状态的变化,请将该逻辑移至
componentDidUpdate
。¥If you need to run a side effect (for example, fetch data, run an animation, or reinitialize a subscription) in response to prop or state changes, move that logic to
componentDidUpdate
instead. -
如果你需要从 DOM 读取某些信息(例如,保存当前滚动位置),以便稍后在
componentDidUpdate
中使用,请改用getSnapshotBeforeUpdate
读取。¥If you need to read some information from the DOM (for example, to save the current scroll position) so that you can use it in
componentDidUpdate
later, read it insidegetSnapshotBeforeUpdate
instead.
¥See examples of migrating away from unsafe lifecycles.
参数
¥Parameters
-
nextProps
:组件即将渲染的下一个属性。比较nextProps
和this.props
以确定发生了什么变化。¥
nextProps
: The next props that the component is about to render with. ComparenextProps
tothis.props
to determine what changed. -
nextState
:组件即将渲染的下一个 state。比较nextState
和this.state
以确定发生了什么变化。¥
nextState
: The next state that the component is about to render with. ComparenextState
tothis.state
to determine what changed.
返回
¥Returns
UNSAFE_componentWillUpdate
不应返回任何内容。
¥UNSAFE_componentWillUpdate
should not return anything.
注意事项
¥Caveats
-
如果
shouldComponentUpdate
已定义并返回false
,则UNSAFE_componentWillUpdate
将不会被调用。¥
UNSAFE_componentWillUpdate
will not get called ifshouldComponentUpdate
is defined and returnsfalse
. -
如果组件实现了
static getDerivedStateFromProps
或getSnapshotBeforeUpdate
。,则UNSAFE_componentWillUpdate
将不会被调用。¥
UNSAFE_componentWillUpdate
will not get called if the component implementsstatic getDerivedStateFromProps
orgetSnapshotBeforeUpdate
. -
在
componentWillUpdate
期间不支持调用setState
(或任何导致调用setState
的方法,例如调度 Redux 操作)。¥It’s not supported to call
setState
(or any method that leads tosetState
being called, like dispatching a Redux action) duringcomponentWillUpdate
. -
尽管
UNSAFE_componentWillUpdate
如此命名,但如果你的应用使用了诸如Suspense
。 之类的现代 React 功能,它并不能保证组件会更新。如果渲染尝试被暂停(例如,由于某些子组件的代码尚未加载),React 将丢弃正在进行的树,并在下一次尝试时尝试从头开始构建组件。下次尝试渲染时,props 和状态可能会有所不同。这就是为什么这个方法是 “unsafe”。仅应在已提交更新时运行的代码(例如重置订阅)应放入componentDidUpdate
。。¥Despite its naming,
UNSAFE_componentWillUpdate
does not guarantee that the component will update if your app uses modern React features likeSuspense
. If a render attempt is suspended (for example, because the code for some child component has not loaded yet), React will throw the in-progress tree away and attempt to construct the component from scratch during the next attempt. By the time of the next render attempt, the props and state might be different. This is why this method is “unsafe”. Code that should run only for committed updates (like resetting a subscription) should go intocomponentDidUpdate
. -
UNSAFE_componentWillUpdate
并不意味着组件接收到的属性或状态与上次不同。你需要自行比较nextProps
与this.props
以及nextState
与this.state
以检查是否有任何变化。¥
UNSAFE_componentWillUpdate
does not mean that the component has received different props or state than the last time. You need to comparenextProps
withthis.props
andnextState
withthis.state
yourself to check if something changed. -
React 在挂载期间不会使用初始属性和状态调用
UNSAFE_componentWillUpdate
。¥React doesn’t call
UNSAFE_componentWillUpdate
with initial props and state during mounting.
static contextType
如果你想从类组件中读取 this.context
,则必须指定它需要读取的上下文。你指定为 static contextType
的上下文必须是先前由 createContext
。 创建的值。
¥If you want to read this.context
from your class component, you must specify which context it needs to read. The context you specify as the static contextType
must be a value previously created by createContext
.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}
static defaultProps
你可以定义 static defaultProps
来设置该类的默认属性。它们将用于 undefined
和缺失的属性,但不用于 null
属性。
¥You can define static defaultProps
to set the default props for the class. They will be used for undefined
and missing props, but not for null
props.
例如,你可以这样定义 color
属性默认为 'blue'
:
¥For example, here is how you define that the color
prop should default to 'blue'
:
class Button extends Component {
static defaultProps = {
color: 'blue'
};
render() {
return <button className={this.props.color}>click me</button>;
}
}
如果未提供 color
属性或 undefined
属性,则默认设置为 'blue'
:
¥If the color
prop is not provided or is undefined
, it will be set by default to 'blue'
:
<>
{/* this.props.color is "blue" */}
<Button />
{/* this.props.color is "blue" */}
<Button color={undefined} />
{/* this.props.color is null */}
<Button color={null} />
{/* this.props.color is "red" */}
<Button color="red" />
</>
static getDerivedStateFromError(error)
如果定义了 static getDerivedStateFromError
,React 会在子组件(包括远端子组件)渲染过程中抛出错误时调用它。这让你可以显示错误消息而不是清除 UI。
¥If you define static getDerivedStateFromError
, React will call it when a child component (including distant children) throws an error during rendering. This lets you display an error message instead of clearing the UI.
通常,它与 componentDidCatch
一起使用,以便你将错误报告发送到某些分析服务。具有这些方法的组件称为错误边界。
¥Typically, it is used together with componentDidCatch
which lets you send the error report to some analytics service. A component with these methods is called an error boundary.
参数
¥Parameters
-
error
:抛出的错误。实际上,它通常是Error
的一个实例,但这并不能保证,因为 JavaScript 允许对任何值进行throw
操作,包括字符串甚至null
。¥
error
: The error that was thrown. In practice, it will usually be an instance ofError
but this is not guaranteed because JavaScript allows tothrow
any value, including strings or evennull
.
返回
¥Returns
static getDerivedStateFromError
应返回告知组件显示错误消息的状态。
¥static getDerivedStateFromError
should return the state telling the component to display the error message.
注意事项
¥Caveats
-
static getDerivedStateFromError
应该是一个纯函数。如果你想要执行副作用(例如,调用分析服务),你还需要实现componentDidCatch
。。¥
static getDerivedStateFromError
should be a pure function. If you want to perform a side effect (for example, to call an analytics service), you need to also implementcomponentDidCatch
.
static getDerivedStateFromProps(props, state)
如果定义了 static getDerivedStateFromProps
,React 将在调用 render
, 之前立即调用它,无论是在初始挂载时还是在后续更新时。此方法应返回一个对象来更新状态,或返回 null
来不更新任何内容。
¥If you define static getDerivedStateFromProps
, React will call it right before calling render
, both on the initial mount and on subsequent updates. It should return an object to update the state, or null
to update nothing.
此方法存在于 罕见用例 中,其状态取决于属性随时间的变化。例如,当 userID
属性发生变化时,此 Form
组件会重置 email
状态:
¥This method exists for rare use cases where the state depends on changes in props over time. For example, this Form
component resets the email
state when the userID
prop changes:
class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};
static getDerivedStateFromProps(props, state) {
// Any time the current user changes,
// Reset any parts of state that are tied to that user.
// In this simple example, that's just the email.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}
// ...
}
请注意,此模式要求你将 prop(如 userID
)的先前值保留在 state(如 prevUserID
)中。
¥Note that this pattern requires you to keep a previous value of the prop (like userID
) in state (like prevUserID
).
参数
¥Parameters
-
props
:组件即将渲染的下一个属性。¥
props
: The next props that the component is about to render with. -
state
:组件即将渲染的下一个 state。¥
state
: The next state that the component is about to render with.
返回
¥Returns
static getDerivedStateFromProps
返回一个对象来更新状态,null
则不更新任何内容。
¥static getDerivedStateFromProps
return an object to update the state, or null
to update nothing.
注意事项
¥Caveats
-
此方法在每次渲染时都会触发,无论原因如何。这与
UNSAFE_componentWillReceiveProps
不同,UNSAFE_componentWillReceiveProps
仅在父组件触发重新渲染时触发,而不是由于本地setState
触发。¥This method is fired on every render, regardless of the cause. This is different from
UNSAFE_componentWillReceiveProps
, which only fires when the parent causes a re-render and not as a result of a localsetState
. -
此方法无法访问组件实例。如果你愿意,你可以通过将组件属性和状态的纯函数提取到类定义之外,在
static getDerivedStateFromProps
和其他类方法之间重用一些代码。¥This method doesn’t have access to the component instance. If you’d like, you can reuse some code between
static getDerivedStateFromProps
and the other class methods by extracting pure functions of the component props and state outside the class definition.
用法
¥Usage
定义类组件
¥Defining a class component
要将 React 组件定义为类,请扩展内置的 Component
类并定义一个 render
方法:。
¥To define a React component as a class, extend the built-in Component
class and define a render
method:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
每当 React 需要确定在屏幕上显示什么时,它都会调用 render
方法。通常,你会从中返回一些 JSX 值。你的 render
方法应该是 纯函数:,它应该只计算 JSX。
¥React will call your render
method whenever it needs to figure out what to display on the screen. Usually, you will return some JSX from it. Your render
method should be a pure function: it should only calculate the JSX.
与 函数组件 类似,类组件可以从其父组件调用 通过属性接收信息。然而,读取属性的语法是不同的。例如,如果父组件渲染了 <Greeting name="Taylor" />
,那么你可以从 this.props
读取 name
属性,就像 this.props.name
一样:
¥Similarly to function components, a class component can receive information by props from its parent component. However, the syntax for reading props is different. For example, if the parent component renders <Greeting name="Taylor" />
, then you can read the name
prop from this.props
, like this.props.name
:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
请注意,类组件内部不支持 Hook(以 use
开头的函数,例如 useState
)。
¥Note that Hooks (functions starting with use
, like useState
) are not supported inside class components.
为类组件添加状态
¥Adding state to a class component
要将 状态 添加到类,请将一个对象分配给名为 state
的属性。要更新状态,请调用 this.setState
。
¥To add state to a class, assign an object to a property called state
. To update state, call this.setState
.
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = () => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Increment age </button> <p>Hello, {this.state.name}. You are {this.state.age}.</p> </> ); } }
为类组件添加生命周期方法
¥Adding lifecycle methods to a class component
你可以在类中定义一些特殊方法。
¥There are a few special methods you can define on your class.
如果定义了 componentDidMount
方法,React 会在组件添加(挂载)到屏幕时调用它。React 会在组件由于属性或状态更改而重新渲染后调用 componentDidUpdate
。React 会在组件从屏幕上移除(卸载)后调用 componentWillUnmount
。
¥If you define the componentDidMount
method, React will call it when your component is added (mounted) to the screen. React will call componentDidUpdate
after your component re-renders due to changed props or state. React will call componentWillUnmount
after your component has been removed (unmounted) from the screen.
如果你实现 componentDidMount
,通常需要实现所有三个生命周期以避免错误。例如,如果 componentDidMount
读取某些状态或属性,你还必须实现 componentDidUpdate
来处理它们的更改,并实现 componentWillUnmount
来清理 componentDidMount
正在执行的操作。
¥If you implement componentDidMount
, you usually need to implement all three lifecycles to avoid bugs. For example, if componentDidMount
reads some state or props, you also have to implement componentDidUpdate
to handle their changes, and componentWillUnmount
to clean up whatever componentDidMount
was doing.
例如,此 ChatRoom
组件通过属性和状态保持聊天连接同步:
¥For example, this ChatRoom
component keeps a chat connection synchronized with props and state:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> Server URL:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Welcome to the {this.props.roomId} room!</h1> </> ); } }
请注意,在开发环境中,当 严格模式 处于启用状态时,React 将调用 componentDidMount
,立即调用 componentWillUnmount
,然后再次调用 componentDidMount
。这可以帮助你注意到是否忘记实现 componentWillUnmount
,或者它的逻辑是否没有完全实现 componentDidMount
的功能。
¥Note that in development when Strict Mode is on, React will call componentDidMount
, immediately call componentWillUnmount
, and then call componentDidMount
again. This helps you notice if you forgot to implement componentWillUnmount
or if its logic doesn’t fully “mirror” what componentDidMount
does.
使用错误边界捕获渲染错误
¥Catching rendering errors with an error boundary
默认情况下,如果你的应用在渲染过程中抛出错误,React 将从屏幕上移除其 UI。为了防止这种情况,你可以将部分 UI 封装到错误边界中。错误边界是一个特殊的组件,它允许你显示一些回退 UI 来代替崩溃的部分,例如一条错误消息。
¥By default, if your application throws an error during rendering, React will remove its UI from the screen. To prevent this, you can wrap a part of your UI into an error boundary. An error boundary is a special component that lets you display some fallback UI instead of the part that crashed—for example, an error message.
要实现错误边界组件,你需要提供 static getDerivedStateFromError
,它允许你在发生错误时更新状态并向用户显示错误消息。你还可以选择实现 componentDidCatch
来添加一些额外的逻辑,例如,将错误记录到分析服务中。
¥To implement an error boundary component, you need to provide static getDerivedStateFromError
which lets you update state in response to an error and display an error message to the user. You can also optionally implement componentDidCatch
to add some extra logic, for example, to log the error to an analytics service.
使用 captureOwnerStack
,你可以在开发过程中包含 Owner Stack。
¥With captureOwnerStack
you can include the Owner Stack during development.
import * as React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, info) {
logErrorToMyService(
error,
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
info.componentStack,
// Warning: `captureOwnerStack` is not available in production.
React.captureOwnerStack(),
);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback;
}
return this.props.children;
}
}
然后你可以用它来封装组件树的一部分:
¥Then you can wrap a part of your component tree with it:
<ErrorBoundary fallback={<p>Something went wrong</p>}>
<Profile />
</ErrorBoundary>
如果 Profile
或其子组件抛出错误,ErrorBoundary
将 “catch” 该错误,显示一个包含你提供的错误消息的回退 UI,并向你的错误报告服务发送生产错误报告。
¥If Profile
or its child component throws an error, ErrorBoundary
will “catch” that error, display a fallback UI with the error message you’ve provided, and send a production error report to your error reporting service.
你无需将每个组件封装到单独的错误边界中。考虑 错误边界的粒度 时,请考虑在哪里显示错误消息是合理的。例如,在消息应用中,在对话列表周围放置一个错误边界是有意义的。在每条消息周围放置一个 也是合理的。但是,为每个头像设置边界是没有意义的。
¥You don’t need to wrap every component into a separate error boundary. When you think about the granularity of error boundaries, consider where it makes sense to display an error message. For example, in a messaging app, it makes sense to place an error boundary around the list of conversations. It also makes sense to place one around every individual message. However, it wouldn’t make sense to place a boundary around every avatar.
备选方案
¥Alternatives
将简单组件从类迁移到函数
¥Migrating a simple component from a class to a function
通常,你将使用 将组件定义为函数。
¥Typically, you will define components as functions instead.
例如,假设你正在将此 Greeting
类组件转换为函数:
¥For example, suppose you’re converting this Greeting
class component to a function:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
定义一个名为 Greeting
的函数。这是你将 render
函数主体移动到的位置。
¥Define a function called Greeting
. This is where you will move the body of your render
function.
function Greeting() {
// ... move the code from the render method here ...
}
定义 name
属性 使用解构语法 并直接读取它,而不是 this.props.name
:
¥Instead of this.props.name
, define the name
prop using the destructuring syntax and read it directly:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
这是一个完整的示例:
¥Here is a complete example:
function Greeting({ name }) { return <h1>Hello, {name}!</h1>; } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
将带有状态的组件从类迁移到函数
¥Migrating a component with state from a class to a function
假设你将这个 Counter
类组件转换为一个函数:
¥Suppose you’re converting this Counter
class component to a function:
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = (e) => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Increment age </button> <p>Hello, {this.state.name}. You are {this.state.age}.</p> </> ); } }
首先,声明一个包含必要 状态变量: 的函数。
¥Start by declaring a function with the necessary state variables:
import { useState } from 'react';
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...
接下来,转换事件处理程序:
¥Next, convert the event handlers:
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
function handleNameChange(e) {
setName(e.target.value);
}
function handleAgeChange() {
setAge(age + 1);
}
// ...
最后,将所有以 this
开头的引用替换为你在组件中定义的变量和函数。例如,将 this.state.age
替换为 age
,将 this.handleNameChange
替换为 handleNameChange
。
¥Finally, replace all references starting with this
with the variables and functions you defined in your component. For example, replace this.state.age
with age
, and replace this.handleNameChange
with handleNameChange
.
这是一个完全转换的组件:
¥Here is a fully converted component:
import { useState } from 'react'; export default function Counter() { const [name, setName] = useState('Taylor'); const [age, setAge] = useState(42); function handleNameChange(e) { setName(e.target.value); } function handleAgeChange() { setAge(age + 1); } return ( <> <input value={name} onChange={handleNameChange} /> <button onClick={handleAgeChange}> Increment age </button> <p>Hello, {name}. You are {age}.</p> </> ) }
将带有生命周期方法的组件从类迁移到函数
¥Migrating a component with lifecycle methods from a class to a function
假设你将这个包含生命周期方法的 ChatRoom
类组件转换为一个函数:
¥Suppose you’re converting this ChatRoom
class component with lifecycle methods to a function:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> Server URL:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Welcome to the {this.props.roomId} room!</h1> </> ); } }
首先,验证你的 componentWillUnmount
是否与 componentDidMount
。 执行相反的操作。在上面的例子中,情况确实如此:它会断开 componentDidMount
建立的连接。如果缺少此类逻辑,请先添加。
¥First, verify that your componentWillUnmount
does the opposite of componentDidMount
. In the above example, that’s true: it disconnects the connection that componentDidMount
sets up. If such logic is missing, add it first.
接下来,验证你的 componentDidUpdate
方法是否能够处理你在 componentDidMount
中使用的任何属性和状态的变更。在上面的例子中,componentDidMount
调用 setupConnection
,后者读取 this.state.serverUrl
和 this.props.roomId
。这就是为什么 componentDidUpdate
会检查 this.state.serverUrl
和 this.props.roomId
是否已更改,并在更改后重置连接。如果你的 componentDidUpdate
逻辑缺失或无法处理所有相关属性和状态的变更,请先修复该逻辑。
¥Next, verify that your componentDidUpdate
method handles changes to any props and state you’re using in componentDidMount
. In the above example, componentDidMount
calls setupConnection
which reads this.state.serverUrl
and this.props.roomId
. This is why componentDidUpdate
checks whether this.state.serverUrl
and this.props.roomId
have changed, and resets the connection if they did. If your componentDidUpdate
logic is missing or doesn’t handle changes to all relevant props and state, fix that first.
在上面的例子中,生命周期方法中的逻辑将组件连接到 React 外部的系统(聊天服务器)。要将组件连接到外部系统 将此逻辑描述为单个副作用:
¥In the above example, the logic inside the lifecycle methods connects the component to a system outside of React (a chat server). To connect a component to an external system, describe this logic as a single Effect:
import { useState, useEffect } from 'react';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
此 useEffect
调用等同于上述生命周期方法中的逻辑。如果你的生命周期方法执行多个不相关的操作,将它们拆分为多个独立的副作用。 以下是一个完整的示例,你可以参考:
¥This useEffect
call is equivalent to the logic in the lifecycle methods above. If your lifecycle methods do multiple unrelated things, split them into multiple independent Effects. Here is a complete example you can play with:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId, serverUrl]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); }
将带有上下文的组件从类迁移到函数
¥Migrating a component with context from a class to a function
在此示例中,Panel
和 Button
类组件从 this.context
: 读取 上下文。
¥In this example, the Panel
and Button
class components read context from this.context
:
import { createContext, Component } from 'react'; const ThemeContext = createContext(null); class Panel extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'panel-' + theme; return ( <section className={className}> <h1>{this.props.title}</h1> {this.props.children} </section> ); } } class Button extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'button-' + theme; return ( <button className={className}> {this.props.children} </button> ); } } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }
当你将它们转换为函数组件时,用 useContext
调用替换 this.context
:
¥When you convert them to function components, replace this.context
with useContext
calls:
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }