使用 Effect Hook( Day17 )

上一篇介绍过 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


<<:  Day#16 Database manager

>>:  [Day 16] MySQL下载注意事项(Mac版)

Adaptor 转接器模式

今天开始要介绍 Structural patterns。先前的 Creational pattern...

Day 9:使用 Typora 发表你的第一篇 Hexo 文章

今天我们正式要使用 Markdown 撰写你的第一篇部落格文章啦! 用指令建立文章或草稿 .md 档...

连续 30 天 玩玩看 ProtoPie - Day 9

做出左右滑动的互动行为 今天要来操作这个 Container ,其实就可以把它想成「一组」东西就好了...

从 IT 技术面细说 Search Console 的 27 组数字 KPI (22) :KPI 总表,项目流程次序

从 IT 技术面细说 Search Console 的 27 组数字 KPI (22) :KPI 总...

Day 19 - 网页元素DOM - 表单元件的Event,表单的type 设定

制作表单 createRadio(); 沿用上一个文章的参考 加上以下设定 我们可以用radio去做...