react hook -- useEffect

使用Effect hook可以在函數(shù)組件中執(zhí)行副作用

副作用 - 指一段和當(dāng)前執(zhí)行結(jié)果無關(guān)的代碼。

  • data fetching
  • setting up a subscription
  • manually changing the DOM
  • logging

useEffect 可以看作是 componentDidMount, componentDidUpdatecomponentWillUnmount 的結(jié)合,且useEffect不會(huì)阻塞瀏覽器更新screen。

useEffect 使用方法及執(zhí)行時(shí)機(jī):

  1. Effects Without Cleanup - 該例子會(huì)在每次render之后都執(zhí)行effect
    • 組建掛載后-componentDidMount
    • 每次update后-componentDidUpdate
useEffect(() => {
  document.title = `You clicked ${count} times`;
})
  1. Effects With Cleanup - 該例子的effect返回了一個(gè)函數(shù)
    • 其他內(nèi)容在每次render之后會(huì)執(zhí)行
    • 返回的函數(shù)內(nèi)容會(huì)在組件卸載之前(等同于componentWillUnmount)執(zhí)行
useEffect(() => {
  const handStatusUpdated = (status) => {
    setIsOnline(status.isOnline)
  }
  ChatAPI.subscribe(friend.id, handStatusUpdated);
  return ChatAPI.unsubscribe(friend.id, handStatusUpdated);
})
  1. 在同一個(gè)組件中多次使用useEffect - React會(huì)按照指定的順序應(yīng)用每個(gè)effect
  2. Skipping Effects - 只有count改變才會(huì)re-runeffect
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count])
useEffect(() => {
  const handStatusUpdated = (status) => {
    setIsOnline(status.isOnline)
  }
  ChatAPI.subscribe(friend.id, handStatusUpdated);
  return ChatAPI.unsubscribe(friend.id, handStatusUpdated);
}, [friend.id])
  1. 只在mountunmount時(shí)運(yùn)行的effect - 依賴項(xiàng)傳入空數(shù)組并返回函數(shù)
useEffect(() => {
  // code block mount時(shí)執(zhí)行
  return () => {
    // code block unmount時(shí)執(zhí)行
  }
}, [])

Hooks 的依賴項(xiàng)

Hooks 提供了讓你監(jiān)聽某個(gè)數(shù)據(jù)變化的能力。這個(gè)變化可能會(huì)觸發(fā)組件的刷新,也可能是去創(chuàng)建一個(gè)副作用,又或者是刷新一個(gè)緩存。那么定義要監(jiān)聽哪些數(shù)據(jù)變化的機(jī)制,其實(shí)就是指定 Hooks 的依賴項(xiàng)。

定義依賴項(xiàng)時(shí),需要注意以下三點(diǎn):

  • 依賴項(xiàng)中定義的變量一定是會(huì)在回調(diào)函數(shù)中用到的,否則聲明依賴項(xiàng)其實(shí)是沒有意義的。
  • 依賴項(xiàng)一般是一個(gè)常量數(shù)組,而不是一個(gè)變量。因?yàn)橐话阍趧?chuàng)建 callback 的時(shí)候,你其實(shí)非常清楚其中要用到哪些依賴項(xiàng)了。
  • React 會(huì)使用淺比較對(duì)比依賴項(xiàng)是否發(fā)生了變化,所以要特別注意數(shù)組或者對(duì)象類型。
function Sample() {
  // 這里在每次組件執(zhí)行時(shí)創(chuàng)建了一個(gè)新數(shù)組
  const todos = [{ text: 'Learn hooks.'}];
  useEffect(() => {
    console.log('Todos changed.');
  }, [todos]);
}

代碼的原意可能是在 todos 變化的時(shí)候去產(chǎn)生一些副作用,但是這里的 todos 變量是在函數(shù)內(nèi)創(chuàng)建的,實(shí)際上每次都產(chǎn)生了一個(gè)新數(shù)組。

useEffect 與三種生命周期方法


useEffect(() => {
  // componentDidMount + componentDidUpdate
  console.log('這里基本等價(jià)于 componentDidMount + componentDidUpdate');
  return () => {
    // componentWillUnmount
    console.log('這里基本等價(jià)于 componentWillUnmount');
  }
}, [deps])

基本等價(jià)于的含義:

  • 一方面,useEffect(callback) 這個(gè) Hook 接收的 callback,只有在依賴項(xiàng)變化時(shí)才被執(zhí)行。而傳統(tǒng)的 componentDidUpdate 則一定會(huì)執(zhí)行。在componentDidUpdate 中,我們通常都需要手動(dòng)判斷某個(gè)狀態(tài)是否發(fā)生變化,然后再執(zhí)行特定的邏輯。
  • 另一方面,callback 返回的函數(shù)(一般用于清理工作)在下一次依賴項(xiàng)發(fā)生變化以及組件銷毀之前執(zhí)行,而傳統(tǒng)的 componentWillUnmount 只在組件銷毀時(shí)才會(huì)執(zhí)行。

useEffect 接收的返回值是一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)不只是會(huì)在組件銷毀時(shí)執(zhí)行,而且是每次 Effect 重新執(zhí)行之前都會(huì)執(zhí)行,用于清理上一次 Effect 的執(zhí)行結(jié)果。

總結(jié)

學(xué)習(xí)useEffect要理解什么是副作用以及使用useEffect傳入不同的參數(shù)時(shí)能達(dá)到什么效果。雖然 Hooks 在功能上基本可以映射到傳統(tǒng)的 Class 組件的生命周期方法,但是它們卻又不是完全等價(jià)的。在實(shí)現(xiàn)具體的業(yè)務(wù)功能的時(shí)候,都應(yīng)該盡量從 Hooks 的語義角度出發(fā)去思考組件是如何展現(xiàn)和交互的,這樣才能更加順滑地切換到函數(shù)組件的開發(fā)方式。

在函數(shù)組件中你要思考的方式永遠(yuǎn)是:當(dāng)某個(gè)狀態(tài)發(fā)生變化時(shí),我要做什么,而不再是在 Class 組件中的某個(gè)生命周期方法中我要做什么。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容