📌  相关文章
📜  反应JS |使用效果挂钩

📅  最后修改于: 2022-05-13 01:56:18.614000             🧑  作者: Mango

反应JS |使用效果挂钩

引入 useEffect Hook 背后的动机是消除使用基于类的组件的副作用。例如,更新 DOM、从 API 端点获取数据、设置订阅或计时器等任务可能会导致不必要的副作用。由于渲染方法会快速产生副作用,因此需要使用生命周期方法来观察副作用。例如,考虑将简单计数器组件的文档标题更新为当前值。在初始渲染时,我们将当前点击值设置为 0 次点击。因此,这部分被编码到 componentDidMount() 方法中,该方法在组件生命周期中只执行一次。然后我们创建一个按钮,在每次点击时将计数状态值加一。随着计数值状态的变化,我们还需要再次更新文档标题,为此,我们需要在 componentDidUpdate() 中编写相同的代码。 componentDidupdate() 方法非常适合在状态更改时随时更新计数器值,但代码的重复是副作用之一。

Javascript
componentDidMount(){
    document.title = `you clicked ${this.state.count} times`;
}
 
componentDidUpdate(){
    document.title = `you clicked ${this.state.count} times`;
}


Javascript
componentDidMount(){
    this.interval = setInterval(this.tick, 1000)
}
 
componentWillUnmount(){
    clearInterval(this.interval)
}


Javascript
componentDidMount(){
    document.title = `you clicked ${this.state.count} times`;
    this.interval = setInterval(this.tick, 1000)
 
}
 
componentDidUpdate(){
    document.title = `you clicked ${this.state.count} times`;
    clearInterval(this.interval)
}


Javascript
import React, { Component } from 'react'
 
class ClassCounterOne extends Component {
    constructor(props){
        super(props)
        this.state = {
            count: 0
        }
    }
 
componentDidMount(){
    document.title = `Clicked ${this.state.count} times`
}
 
componentDidUpdate(prevProps, prevState){
    document.title = `Clicked ${this.state.count} times`
}
 
render() {
    return (
        
                     
    ) }   export default ClassCounterOne


Javascript
import React from 'react'
import './App.css'
import ClassCounterOne from './components/classCounterOne'
 
function App(){
    return(
        
                 
    ) }   export default App


Javascript
import React, { useState, useEffect } from 'react'
 
function HookCounterOne() {
    const [count, setCount] = useState(0)
 
    useEffect(() => {
        document.title = `You clicked ${count} times`
 
    return (
        
                     
    ) } export default HookCounterOne


Javascript
import React from 'react'
import './App.css'
import ClassCounterOne from './components/classCounterOne'
 
function App(){
    return(
        
                 
    ) }   export default App


让我们通过设置一个计时器来考虑另一个副作用。在 componentDidMount() 方法中,我们设置了一个计时器,每 5 秒记录一个字符串“hello”。当组件从 DOM 中移除时,我们可以清除这个计时器。我们在 componentWillUnmount() 生命周期方法中这样做。所以计时器的代码如下所示:

Javascript

componentDidMount(){
    this.interval = setInterval(this.tick, 1000)
}
 
componentWillUnmount(){
    clearInterval(this.interval)
}

合并形成单个组件时的计数器和计时器都如下所示:

Javascript

componentDidMount(){
    document.title = `you clicked ${this.state.count} times`;
    this.interval = setInterval(this.tick, 1000)
 
}
 
componentDidUpdate(){
    document.title = `you clicked ${this.state.count} times`;
    clearInterval(this.interval)
}

当您观察上面的代码时,我们倾向于注意到为了更新文档标题,我们编写了两次相同的代码,一次在 componentDidmount() 中,一次在 componentDidUpdate() 中。要观察的第二件事是如何将代码拆分为组件。与定时器相关的代码、setInterval、clearInterval相关的代码放在不同的代码块中(即不同的生命周期方法)。更新DOM的代码和设置定时器的完全不相关的代码放在同一个生命周期方法中(即在componentDidMount()中)。如果可以选择不重复代码同时将相关代码组合在同一个块中,那就更好了。这就是 useEffect Hook 出现在图片中的地方。
Effect Hook 允许您在功能组件中执行副作用。它是 componentDidMount()、componentDidUpdate() 和 componentWillUnmount() 方法的完美替代品。

渲染后的 useEffect:我们知道,useEffect() 用于在功能组件中产生副作用,它还能够将基于类的组件的 componentDidMount()、componentDidUpdate() 和 componentWillUnmount() 生命周期方法处理为功能组件.让我们看一个示例,说明如何将 useEffect 钩子用作可以模仿上述生命周期方法但在功能组件中的功能。

为了更好地理解,让我们看看下面的类组件中的代码是什么样的,我们将其命名为“ClassComponentOne”

文件名:src/components/ClassCounterOne.js

Javascript

import React, { Component } from 'react'
 
class ClassCounterOne extends Component {
    constructor(props){
        super(props)
        this.state = {
            count: 0
        }
    }
 
componentDidMount(){
    document.title = `Clicked ${this.state.count} times`
}
 
componentDidUpdate(prevProps, prevState){
    document.title = `Clicked ${this.state.count} times`
}
 
render() {
    return (
        
                     
    ) }   export default ClassCounterOne

现在,我们将组件包含在 App.js 中。 App.js 的代码如下所示

文件名:src/App.js

Javascript

import React from 'react'
import './App.css'
import ClassCounterOne from './components/classCounterOne'
 
function App(){
    return(
        
                 
    ) }   export default App

现在,如果我们查看浏览器,我们可以观察到最初的文档标题是“Clicked 0 times”。

初始状态

如果我们单击按钮,每次单击时计数值都会增加 1 并更新标题。

现在让我们尝试用功能组件替换功能。出于同样的目的,创建一个新文件并将其命名(例如,HookCounterOne.js)

功能组件将如下面的代码所示:

文件名:src/components/HookCounterOne.js

Javascript

import React, { useState, useEffect } from 'react'
 
function HookCounterOne() {
    const [count, setCount] = useState(0)
 
    useEffect(() => {
        document.title = `You clicked ${count} times`
 
    return (
        
                     
    ) } export default HookCounterOne

现在我们需要在我们的 App.js 文件中导入上述组件。包含 HookCounterOne 组件后,代码如下所示:

文件名:src/App.js

Javascript

import React from 'react'
import './App.css'
import ClassCounterOne from './components/classCounterOne'
 
function App(){
    return(
        
                 
    ) }   export default App

现在,如果我们查看浏览器,我们可以看到如下所示的初始状态。最初,文档标题为“您点击了 0 次”。

并且当您单击按钮时,计数值会增加,并且文档标题会更新。正如我们所观察到的,行为符合预期。

当我们指定 useEffect 时,我们基本上是在每次组件渲染时请求响应执行我们作为参数传入 useEffect函数的函数。第二点要注意的是 useEffect 是在组件内部使用的,因为这样做我们可以很容易地访问组件的状态和道具,而无需编写任何额外的代码。