Re: 新手让网页 act 起来: Day12 - React hooks 之 useEffect

昨天我们介绍完 React 最常用的 useState hook,今天就来聊聊在第二常用的 useEffect hook 吧!

根据官网的说明,useEffect 在 function component 是扮演着处理 side effect 的角色。

看完上面简短的说明,相信应该会有一个疑问是说,什麽是 side effect?首先要了解 side effect 我们先来简单了解一下什麽是 pure function。

Pure function

Pure function 指的是当相同的输入,永远会得到相同的输出,而且没有任何显着的副作用。例如:

function double(x){
  return 2 * x
}
double(2) // 4
double(2) // 4
double(2) // 4

在上面 double 函式中,我们很单纯的只做运算,而且输入相同的值 2,都只会输出 4。

那到底怎麽样算是一个副作用呢?例如:

let doNotChange = 10

function double(x){
  console.log('hello') //  副作用
  
  doNotChange += 5 //  副作用
  return 2 * x
}


double(2) // 4
double(2) // 4
double(2) // 4

以上面的例子来看,我们呼叫 console.log() 更动浏览器的主控台的输出,或是更动到外部的变数,像这样有更动到外部环境都具有副作用。

副作用并不代表一定是不好的,而是它有可能会影响到其他环境的使用情况。

useEffect

初步了解什麽是 pure function 及 side effect 之後,我们可以试想把 function component 作为一个 pure function 来看待。当我们传入的 props 都是固定的,那回传的 UI 就会是一样的。而其他的,例如: 串接第三方 api 或是呼叫浏览器的 api 等等,都会被归类为 side effect。

而 useEffect 这个 hook 就是设计来处理并执行这些 side effect 的。

以下是 useEffect 的使用方式。

useEffect(()=>{
    // 每一次 render 後会执行
})

useEffect(()=>{
    // 只有在第一次 render 後执行
}, [])

useEffect(()=>{
    // 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
}, [count])

useEffect(()=>{
    // 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里
    return ()=>{
    // 第一次 render 不执行,第二次重新 render 後先执行这个函式
    }
}, [count])

useEffect 这个函式接收两个参数,第一个参数是函式,要执行的 side effect 会放在这个函式中执行;第二参数则是一个阵列,被称为 dependency array,因为 useEffect 会根据阵列中的值变化而决定第二次 render 後要不要执行第一个被当作参数传进去的函式,如果是空阵列,那 useEffect 只会在第一次 render 过後执行。

让我们在前几天的 useState 的范例加上 useEffect,来观察一下上面这四种使用方式:

const Counter = () => {
  const [count, setCount] = React.useState(0) 
  //使用 useState 建立 Count 状态,并将 0 设为初始状态
  
  
  React.useEffect(()=>{
    // 每一次 render 後会执行
    console.log('No.1') 
  })

  React.useEffect(()=>{
    // 只有在第一次 render 後执行
        console.log('No.2') 
  }, [])

  React.useEffect(()=>{
    // 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
     console.log('No.3') 
  }, [count])

  React.useEffect(()=>{
    // 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里
    console.log('No.4') 
    return ()=>{
    // 第一次 render 不执行,第二次重新 render 後先执行这个函式
      console.log('No.5') 
    }
  }, [count])
  
  console.log('No.6 render component')  // render
  
  const increaseHandler = () => {
    setCount(prev => prev + 1) 
    // 点击 plus 按钮,将 count 加 1 ,并使用 setCount 改变 Count 状态
  }
  
  const decreaseHandler = () => {
    if (count === 0) return
    setCount(prev => prev - 1)
    // 点击 minus 按钮,将 count 减 1 ,并使用 setCount 改变 Count 状态
  }
 
  return (
    <div>
      <button onClick={decreaseHandler}></button>
      <span>{count}</span>
      <button onClick={increaseHandler}></button>
    </div>
  )
};

ReactDOM.render(<Counter />, document.getElementById('root'));

大家可以猜猜看上面六个 console.log ,在第一次 render component 後,印出的顺序会是什麽? 接着当 count 值改变,触发 re-render 後,印出的顺序又会是如何?

第一次 render 的解答:

"No.6 render component" 
"No.1" // 每一次 render 後会执行
"No.2" // 只有在第一次 render 後执行
"No.3" // 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
"No.4" // 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里

第二次 render 的解答:

"No.6 render component" 
"No.5" // 重新 render 後先执行这个函式
"No.1" // 每一次 render 後会执行
"No.3" // 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
"No.4" // 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里

不知道大家有没有猜对呢?

以上就是 useEffect 基本的介绍,有什麽问题都欢迎在下方留言。

该文章同步发布於:我的部落格


<<:  找LeetCode上简单的题目来撑过30天啦(DAY12)

>>:  Day 27 | SQLite资料库(二)

Day 1:为什麽工程师要建立自己的技术部落格?

大家好我是 Gui,一名刚於私立科大资管系毕业的社会新鲜人,这是我第一次参与 IT 铁人赛,既紧张又...

伸缩自如的Flask [day 28] Flask-Mail

在有必要的时候,我们可能需要使用寄信来通知使用者、寄信给公会小姐、 把AI数据视觉化的资料寄给老板。...

[NET Core]Epplus於linux环境下无预设lib的报错与解决

Epplus於linux环境下无预设lib的报错与解决 Epplus为.NET众所皆知的Excel读...

Day_29:让 Vite 来开启你的Vue之 跌入深坑_ Suspense非同步元件(续上集)

Hi Dai Gei Ho~ 我是Winnie ~ 不知道大家记不记得,在昨天文章中我们提到了 如果...

Day 7 : 回圈-用来解决重复的事情

今天要来学习程序语言中非常重要的一个概念(功能)-回圈,回圈到底可以拿来干嘛呢?先来看个例子: 如果...