iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
自我挑戰組

React 學習之路系列 第 17

使用 Effect Hook( Day17 )

  • 分享至 

  • xImage
  •  

上一篇介紹過 State Hook 用來儲存狀態,Effect Hook 則用來處理 function component 中的副作用,像是資料 fetch、或手動改變 DOM 等等。使用 Class 跟 Effect Hook 差別能感受到不同切割 React 更新的邏輯,從固定的時間到更大彈性的 render 前後變化。 Effect Hook 對照 Class 生命週期也可以看作是 componentDidMount,componentDidUpdate 和 componentWillUnmount 的組合,夠大的意義是將這些分散的不同地方的邏輯,但其實是 建構與清除(ex: addEventListener, removeEventListener, setTimeout, clearTimeout) 成對的邏輯,重新集中關注點。

Effect Hook 例子重提

function TestUseState() {
  const [title, setTitle] = React.useState("I am waiting...");
  const [count, setCount] = React.useState(0);
  
  React.useEffect(() => {
    
    async function getTitle() {
      let response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
      response = await response.json()
      setTitle(response.title)
    }
  
   getTitle()
  });

 React.useEffect(() => {
   // 使用瀏覽器 API 更新文件標題
   document.title = `You clicked ${count} times`;
 });

  return (
    <div>
      <h1>Hello UseEffect Hook</h1>
      <h3>Title Async : { title }</h3>
      <h3>Title Count : { count } times</h3>
<button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  )
}

Codepen 完整

React component 的兩種 side effect:

  • 無需清除的 Effect
  • 需要清除的 Effect

當 side effect 使用到 setTimeout 、監聽事件或其他外部資源時,就需要注意去清除 timer、listener 或外部資源 socket 等。而清除使用 return function 的方式,

useEffect(() => {
  const timer = setTimeout(() => {
    console.log('This will run after 1 second!')
  }, 1000);
  return () => clearTimeout(timer);
}, []);

使用 Effect 的提示

useEffect 有什麼作用?

告訴 React 你的 component 需要在 render 後做一些事情。通常 componentDidMount 和 componentWillUnmount 成對的,但生命週期中只會執行一次,而中間如有變化可能會造成錯誤。也就是為什麼 在 component 內部呼叫 useEffect,比起用時間週期來切分, render 前後切分降低在撰寫 建造與清除 的程式可以更集中。

為什麼在 component 內部呼叫 useEffect?

=> 只執行一次 unmounting 可能發生的錯誤,當中間又觸發 prop ,unsubscribe 的部分可能 cancel 掉錯誤的 id 造成 memory leak。

Class Component 的 Bug 例子:

componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
}

componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
}

每次 render 後都會執行 useEffect 嗎?

=> 使用第二個參數,可以夠有效率的監控資料變化

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]);

以上今天。

參考資料:
https://zh-hant.reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
https://stackoverflow.com/questions/61885496/how-to-cancel-socket-io-client-subscription-in-react


上一篇
使用 State Hook (Day16)
下一篇
Hook 的規則 ( Day18 )
系列文
React 學習之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言