Skip to content

memo和useMemo

memo在props不变情况下跳过重新渲染,可以达到一些性能优化。

1. 使用memo

如果我们有多个组件,改变其中一个也会让其他组件一起渲染:

jsx
import { useState } from 'react'

function Head() {
  return (
    <div>
      Head 组件
      {Math.random()}
    </div>
  )
}

function App() {
  const [num, setNum] = useState(0)
  const clickHandle = ()=>{
    setNum(num+1)
  }

  return (
    <div>
      <button onClick={clickHandle}>点击</button>
      {num}
      <Head />
    </div>
  )
}
export default App

运行效果:
Alt text 使用memo后:

jsx
import { useState, memo } from 'react'
// 使用memo,将之前的head组件包起来
const Head = memo(function Head() {
  return (
    <div>
      Head 组件
      {Math.random()}
    </div>
  )
})

function App() {
  const [num, setNum] = useState(0)
  const clickHandle = ()=>{
    setNum(num+1)
    console.log(num)
  }

  return (
    <div>
      <button onClick={clickHandle}>点击</button>
      {num}
      <Head />
    </div>
  )
}
export default App

运行可以看到Head组件跳过了渲染:
Alt text 但如果进行了传值,传的值有变化就还是会渲染:

jsx
import { useState, memo } from 'react'

const Head = memo(function Head() {
  return (
    <div>
      Head 组件
      {Math.random()}
    </div>
  )
})

function App() {
  const [num, setNum] = useState(0)
  const clickHandle = ()=>{
    // setNum(1) Head组件只会渲染1次
    // 每次num都会发生改变,每次还是会渲染Head组件
    setNum(num+1)
    console.log(num)
  }

  return (
    <div>
      <button onClick={clickHandle}>点击</button>
      {num}
      <Head items={num}/>
    </div>
  )
}

export default App

如果传值不是简单值而是对象或者数组,即使传值没有改变也会触发Head组件渲染,因为底层是通过Object.is()进行比较新旧值,内存地址变了也算。

2. 使用useMemo缓存数据

使用useMemo可以缓存对象或者数组的值,避免实际没有改变的传值而被渲染组件:

jsx
import { useState, memo, useMemo } from 'react'

const Head = memo(function Head() {
  return (
    <div>
      Head 组件
      {Math.random()}
    </div>
  )
})

function App() {
  const [num, setNum] = useState(0)
  const [msg, setMsg] = useState('hello')
  // Head组件中传入msgArr, 虽然点击按钮修改的是num值,但是也会渲染Head
  const msgArr = [msg.toUpperCase(), msg.toLowerCase()]
  // 将数组数据缓存起来,不同的作用域都可以使用相同的对象,Head组件不会渲染
  // 第二个参数表示依赖项,比如指定msg改了后缓存更新
  const list = useMemo(()=> [msg.toUpperCase(), msg.toLowerCase()], [msg])
  const clickHandle = ()=>{
    setNum(num+1)
    console.log(num)
  }

  return (
    <div>
      <button onClick={clickHandle}>点击</button>
      {num}
      <Head items={list}/>
    </div>
  )
}

export default App

运行效果:
Alt text