Re: 新手让网页 act 起来: Day23 - useCallback 与 React.memo

昨天介绍了 useCallback 的基本使用方式。今天来介绍如何使用 useCallback 与 React.memo 来减少 render 次数。

首先,先来复习一下什麽情况下,会造成 re-render:

  1. 元件的任一 props 或 state 更新
  2. 父层元件更新
function Button({ count, increament }) {
  console.log('%c Button component render', 'color: red')

  return <button onClick={increament}>{count}</button>
}

function Description() {
  console.log('%c Description render', 'color: green')

  return <div>click the button</div>
}

function App() {
  const [count, setCount] = React.useState(0)
  const increament = () => {
    setCount(count + 1)
  }

  console.log('%c App render', 'color: yellow')

  return (
    <div>
      <Button count={count} increament={increament} />
      <Description />
    </div>
  )
}

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

当我们 App 的 count state 改变时,会触发 re-render ,底下的元件不管有没有传递 props 或是 state 都会一起 re-render。

假设有个情况是我们需要 render list

function Button({ count, increament }) {
  return <button onClick={increament}>{count}</button>
}

function MyList({ content, onClickHandler }) {
  console.log(`${content} MyList render`)

  return (
    <div onClick={onClickHandler}>
      {content}
    </div>)
}

function App() {
  const [count, setCount] = React.useState(0)
  const [list, setList] = React.useState(['1', '2', '3', '4', '5'])

  const increament = () => {
    setCount(count + 1)
  }

  const clickItem = (e) => {
    console.log(`click the ${e.target.textContent} item`)
  }

  console.log('%c App render', 'color: yellow')

  return (
    <div>
      <Button count={count} increament={increament} />
      {list.map(item => <MyList key={item} content={item} onClickHandler={clickItem} />)}
    </div>
  )
}

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

当我们点下按钮改变 count 时,我们的所有的 list item 都会 re-render,可以 count 改变跟 list 一点关系都没有。当我们这个 list 越来越多,render 也会增加,这样的情况就可以考虑使用 React.memo 将 MyList 元件包起来。

React.memo 与 useCallback

memo 这个是一个 HOC (High oreder component) ,接收一个元件并回传一个元件,这过程中 memo 跟 useCallback 很类似,它会去记住传进去的元件,并对照每一次 re-render 传进来的值是不是有改变,去决定要不要 re-render 。

所以使用 React.memo 将 MyList 包起来後,就会去比对 content 跟 onClickHandler 是不是有变化,有变化就 re-render 。

const MyList = React.memo(({ content, onClickHandler }) => {
  console.log(`${content} MyList render`)

  return (
    <div onClick={onClickHandler}>
      {content}
    </div>)
})

这个时候当我们再次按下按钮改变 count state ,MyList 元件还是依然,re-render。为什麽呢?原因就是因为 onClickHandler 每一次都是新的实体。所以,这个时候就轮到 useCallback 登场了!

const clickItem = React.useCallback((e) => {
  console.log(`click the ${e.target.textContent} item`)
}, [])

使用 useCallback 之後我们的 MyList 就不会因为 count 改变而 re-render 了!

以上是可以考虑使用 useCallback 的情境。

今天就先介绍到这边,如果有任何问题都欢迎在下方留言!

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


<<:  D24 / 什麽时候我的 Composable function 会重新被呼叫 - recompose

>>:  Day 23 ATT&CK for ICS - Lateral Movement(1)

日志集中管理

在我工作第三个月的时候,夥伴们觉得除错的方式能不能有所改善,於是有提出 EFK 架构,也就是 Ela...

Vue.js 从零开始:watch

watch监听器 监听data里面的值,当值有变化时,就会触发事件。 watch监听一个变数: &l...

RISC-V on Rust 从零开始(6) - 使用Spike模拟器

其实RISC-V官方也有开发了一个instruction accurate等级的模拟器Spike,只...

Day25. Form 里面还有 Form 怎麽办?- 表单 part3

Day23 的弹跳视窗元件,送出表单按钮在form标签的外面,理当来说form 外面的送出表单按钮和...

Day 15 讯息伫列的储存、接收及传送

关於讯息伫列怎麽去储存呢?大致分成下列两种: 1.系统池(system pool):如果能确定讯息伫...