Skip to content

useMemo

介绍

useMemo 是 React 中的一个 Hook,用于在函数组件中优化性能。它可以记住计算结果,避免在每次渲染时都进行重复计算。

快速入门

语法

ts
const memoizedValue = useMemo<T>(factory: () => T, dependencies: DependencyList)

参数说明:

  1. factory:用于返回需要缓存的值的函数,React 会在初始化和依赖变化时调用它。
  2. dependencies:依赖项数组,只有当数组中的某个值发生改变时,factory 才会重新执行。

提示

useMemo 使用 Object.is 对依赖项逐个比较,和 useEffectuseCallback 的依赖比较规则一致。

示例

tsx
import { useMemo, useState } from 'react'

const allProducts = [
  { id: 1, title: 'React 入门教程', price: 99, category: 'course' },
  { id: 2, title: 'React 实战进阶', price: 199, category: 'course' },
  { id: 3, title: 'TypeScript 速查手册', price: 49, category: 'ebook' },
  { id: 4, title: 'CSS 灵感合集', price: 39, category: 'ebook' },
]

function ProductList() {
  const [keyword, setKeyword] = useState('react')
  const [category, setCategory] = useState('all')

  const filteredProducts = useMemo(() => {
    console.log('🔥 仅在依赖变化时重新计算')

    return allProducts
      .filter((item) => (category === 'all' ? true : item.category === category))
      .filter((item) => item.title.toLowerCase().includes(keyword.toLowerCase()))
  }, [keyword, category])

  return (
    <section style={{ display: 'grid', gap: 12 }}>
      <input value={keyword} placeholder="搜索关键词" onChange={(event) => setKeyword(event.target.value)} />

      <select value={category} onChange={(event) => setCategory(event.target.value)}>
        <option value="all">全部</option>
        <option value="course">课程</option>
        <option value="ebook">电子书</option>
      </select>

      <ul style={{ margin: 0, paddingLeft: 18 }}>
        {filteredProducts.map((product) => (
          <li key={product.id}>
            {product.title} - ¥{product.price}
          </li>
        ))}
      </ul>
    </section>
  )
}

export default ProductList

滥用的后果

  1. 内存开销增加:每个 useMemo/useCallback 都需要内存来进行缓存。
  2. 初始渲染性能下降:React 需要额外的工作来管理这些缓存,对于一些简单计算,缓存开销可能比计算本身还要大。
  3. 代码复杂度增加
    • 满屏的 useMemo/useCallback 会让代码变得冗长,降低可读性。
    • 依赖数组管理增加心智负担。
    • 容易出现依赖遗漏的 bug。

基于 MIT 许可发布