反应生命周期的圆
React组件在其应用生命周期中会经历不同的阶段,尽管幕后发生的事情可能并不明显。
这些阶段包括:
- 挂载
- 更新
- 卸载
- 错误处理
每个阶段都有相应的方法,可以在该阶段对组件执行特定操作。例如,当从网络获取数据时,您可能希望在componentDidMount()
方法(在挂载阶段可用)中调用处理API调用的函数。
了解不同的生命周期方法对于React应用程序的开发至关重要,因为它允许我们在需要时精确地触发操作,而不会与其他操作混淆。本文将介绍每个生命周期,包括可用的方法以及我们使用它们的场景类型。
挂载阶段
将挂载视为组件生命周期的初始阶段。在挂载发生之前,组件尚未存在——它只是DOM中的一闪而过,直到挂载发生并将其作为文档的一部分连接起来。
一旦组件挂载,我们就可以利用许多方法:constructor()
、render()
、componentDidMount()
和static getDerivedStateFromProps()
。每个方法都有其自身的用途,让我们按顺序来看一下。
constructor()
当直接在组件上设置状态以将方法绑定在一起时,需要constructor()
方法。它看起来像这样:
// 一旦输入组件开始挂载... constructor(props) { // ...设置一些props... super(props); // ...在这种情况下,是一个空白用户名... this.state = { username: '' }; // ...然后绑定一个处理输入更改的方法 this.handleInputChange = this.handleInputChange.bind(this); }
重要的是要知道,constructor
是创建组件时调用的第一个方法。组件尚未渲染(即将到来),但DOM已经知道它,我们可以在它渲染之前与它挂钩。因此,这不是我们调用setState()
或引入任何副作用的地方,因为组件仍然处于构建阶段!
我之前写过一篇关于refs的教程,我注意到的一件事是在使用React.createRef()
时,可以在constructor
中设置ref。这是合理的,因为refs用于更改值而无需props或必须使用更新值重新渲染组件:
constructor(props) { super(props); this.state = { username: '' }; this.inputText = React.createRef(); }
render()
render()
方法是组件的标记在前端显示的地方。用户此时可以看到并访问它。如果您曾经创建过React组件,那么您已经熟悉它了——即使您没有意识到——因为它需要输出标记。
class App extends React.Component { // 挂载过程中,请渲染以下内容! render() { return ( <div> <p>Hello World!</p> </div> ) } }
但这并不是render()
的全部用途!它还可以用于渲染组件数组:
class App extends React.Component { render () { return [ <h2 id="JavaScript-Tools">JavaScript Tools</h2>, <frontend></frontend>, <backend></backend> ] } }
甚至组件片段:
class App extends React.Component { render() { return ( <react.fragment><p>Hello World!</p></react.fragment> ) } }
我们还可以使用它来渲染DOM层次结构之外的组件(类似于React Portal):
// 我们正在创建一个门户,允许组件在DOM中移动 class Portal extends React.Component { // 首先,我们创建一个div元素 constructor() { super(); this.el = document.createElement("div"); } // 挂载后,让我们追加组件的子元素 componentDidMount = () => { portalRoot.appendChild(this.el); }; // 如果组件从DOM中移除,那么我们也将其子元素移除 componentWillUnmount = () => { portalRoot.removeChild(this.el); }; // 啊,现在我们可以根据需要渲染组件及其子元素 render() { const { children } = this.props; return ReactDOM.createPortal(children, this.el); } }
当然,render()
可以渲染数字和字符串……
class App extends React.Component { render () { return "Hello World!" } }
以及null或布尔值:
class App extends React.Component { render () { return null } }
componentDidMount()
componentDidMount()
这个名字是否说明了它的含义?此方法在组件挂载(即连接到DOM)后调用。在我撰写的另一篇关于在React中获取数据的教程中,这就是您要向API发出请求以获取数据的地方。
我们可以使用您的fetch方法:
fetchUsers() { fetch(`https://jsonplaceholder.typicode.com/users`) .then(response => response.json()) .then(data => this.setState({ users: data, isLoading: false, }) ) .catch(error => this.setState({ error, isLoading: false })); }
然后在componentDidMount()
钩子中调用该方法:
componentDidMount() { this.fetchUsers(); }
我们还可以添加事件监听器:
componentDidMount() { el.addEventListener() }
很简洁,对吧?
static getDerivedStateFromProps()
这是一个有点冗长的名字,但static getDerivedStateFromProps()
并不像听起来那么复杂。它在挂载阶段的render()
方法之前以及更新阶段之前调用。它返回一个对象来更新组件的状态,或者在没有要更新的内容时返回null
。
为了理解它的工作原理,让我们实现一个计数器组件,它将为其计数器状态设置一个特定值。只有当maxCount
的值更高时,此状态才会更新。maxCount
将从父组件传递。
这是父组件:
class App extends React.Component { constructor(props) { super(props) this.textInput = React.createRef(); this.state = { value: 0 } } handleIncrement = e => { e.preventDefault(); this.setState({ value: this.state.value 1 }) }; handleDecrement = e => { e.preventDefault(); this.setState({ value: this.state.value - 1 }) }; render() { return ( <react.fragment><p>Max count: { this.state.value }</p> - <counter maxcount="{this.state.value}"></counter></react.fragment> ) } }
我们有一个按钮用于增加maxCount
的值,我们将其传递给Counter
组件。
class Counter extends React.Component { state={ counter: 5 } static getDerivedStateFromProps(nextProps, prevState) { if (prevState.counter <p>Count: {this.state.counter}</p> ) } }
在Counter
组件中,我们检查counter
是否小于maxCount
。如果是,我们将counter
设置为maxCount
的值。否则,我们什么也不做。
更新阶段
当组件的props或状态更改时,会发生更新阶段。与挂载一样,更新也有自己的一组可用方法,我们接下来将介绍。也就是说,值得注意的是,render()
和getDerivedStateFromProps()
也会在此阶段触发。
shouldComponentUpdate()
当组件的状态或props更改时,我们可以使用shouldComponentUpdate()
方法来控制组件是否应该更新。此方法在渲染发生之前以及接收状态和props时调用。默认行为为true
。要每次状态或props更改时都重新渲染,我们会这样做:
shouldComponentUpdate(nextProps, nextState) { return this.state.value !== nextState.value; }
当返回false
时,组件不会更新,而是调用render()
方法来显示组件。
getSnapshotBeforeUpdate()
我们可以做的一件事是在某个时间点捕获组件的状态,这就是getSnapshotBeforeUpdate()
的设计目的。它在render()
之后但提交任何新更改到DOM之前调用。返回值作为第三个参数传递给componentDidUpdate()
。
它将先前状态和props作为参数:
getSnapshotBeforeUpdate(prevProps, prevState) { // ... }
在我看来,此方法的用例很少。它是一种您可能不会经常使用到的生命周期方法。
componentDidUpdate()
将componentDidUpdate()
添加到方法列表中,其中名称大致说明了所有内容。如果组件更新,那么我们可以使用此方法在此时与它挂钩,并将其传递给组件的先前props和状态。
componentDidUpdate(prevProps, prevState) { if (prevState.counter !== this.state.counter) { // ... } }
如果您曾经使用过getSnapshotBeforeUpdate()
,您还可以将返回值作为参数传递给componentDidUpdate()
:
componentDidUpdate(prevProps, prevState, snapshot) { if (prevState.counter !== this.state.counter) { // .... } }
卸载阶段
我们在这里几乎看到了挂载阶段的反面。正如您可能预期的那样,卸载发生在组件从DOM中清除并且不再可用时。
我们这里只有一个方法:componentWillUnmount()
这在组件卸载和销毁之前调用。这就是我们想要在组件离开后执行任何必要的清理的地方,例如删除可能在componentDidMount()
中添加的事件监听器,或清除订阅。
// 删除事件监听器 componentWillUnmount() { el.removeEventListener() }
错误处理阶段
组件中可能会出现问题,这可能会导致错误。我们已经有一段时间使用错误边界来帮助解决这个问题。此错误边界组件使用一些方法来帮助我们处理可能遇到的错误。
getDerivedStateFromError()
我们使用getDerivedStateFromError()
来捕获从子组件抛出的任何错误,然后我们使用它来更新组件的状态。
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } render() { if (this.state.hasError) { return ( <h1 id="Oops-something-went-wrong">Oops, something went wrong :(</h1> ); } return this.props.children; } }
在此示例中,当从子组件抛出错误时,ErrorBoundary
组件将显示“哎呀,出现了一些问题”。
componentDidCatch()
虽然getDerivedStateFromError()
适用于在发生副作用(如错误日志记录)的情况下更新组件的状态,但我们应该使用componentDidCatch()
,因为它在提交阶段调用,此时DOM已更新。
componentDidCatch(error, info) { // 将错误记录到服务 }
getDerivedStateFromError()
和componentDidCatch()
都可以在ErrorBoundary
组件中使用:
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, info) { // 将错误记录到服务 } render() { if (this.state.hasError) { return ( <h1 id="Oops-something-went-wrong">Oops, something went wrong :(</h1> ); } return this.props.children; } }
这就是React组件的生命周期!
了解React组件如何与DOM交互是一件很酷的事情。很容易认为会发生一些“魔法”,然后页面上就会出现一些东西。但是React组件的生命周期表明,这种疯狂是有秩序的,它旨在赋予我们很大的控制权,以便从组件到达DOM到它消失的时间发生的事情。
我们在相对较短的空间内涵盖了很多内容,但希望这能让您很好地了解React如何处理组件,以及我们在处理的各个阶段拥有什么样的能力。如果您对这里介绍的任何内容不清楚,请随时提出任何问题,我很乐意尽力提供帮助!
以上是反应生命周期的圆的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

您是否曾经在项目上需要一个倒计时计时器?对于这样的东西,可以自然访问插件,但实际上更多

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...

在元素个数不固定的情况下如何通过CSS选择第一个指定类名的子元素在处理HTML结构时,常常会遇到元素个数不�...
