React 中如何避免不必要的重渲染?

1. React.memo(组件级记忆)

const Child = React.memo(({ data }) => {
  console.log('Child render')
  return <div>{data.name}</div>
})

// 只有 data 变化时才重渲染

2. useMemo / useCallback

function Parent({ items }) {
  const [filter, setFilter] = useState('')

  // ✅ 缓存计算结果
  const filtered = useMemo(() => {
    return items.filter(item => item.includes(filter))
  }, [items, filter])

  // ✅ 缓存函数引用
  const handleClick = useCallback(() => {
    setFilter('')
  }, [])

  return <Child data={filtered} onClick={handleClick} />
}

3. 状态下放

将频繁变化的状态隔离到小组件中:

// ❌ input 变化导致整个组件重渲染
function App() {
  const [text, setText] = useState('')
  const [data, setData] = useState([])
  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <ExpensiveList data={data} />
    </>
  )
}

// ✅ 隔离状态
function App() {
  const [data, setData] = useState([])
  return (
    <>
      <SearchInput />
      <ExpensiveList data={data} />
    </>
  )
}

const SearchInput = React.memo(() => {
  const [text, setText] = useState('')
  return <input value={text} onChange={e => setText(e.target.value)} />
})

4. 虚拟列表

// react-window
import { FixedSizeList } from 'react-window'

const Row = ({ index, style }) => (
  <div style={style}>Row {index}</div>
)

<FixedSizeList height={600} itemCount={10000} itemSize={35}>
  {Row}
</FixedSizeList>

5. 懒加载

const LazyComponent = React.lazy(() => import('./HeavyComponent'))

<Suspense fallback={<Spinner />}>
  <LazyComponent />
</Suspense>

6. key 优化

// ❌ 用 index 做 key(列表变化时性能差)
{items.map((item, index) => <Item key={index} data={item} />)}

// ✅ 用唯一 ID 做 key
{items.map(item => <Item key={item.id} data={item} />)}

7. CSS 替代条件渲染

// ❌ 频繁挂载/卸载
{isVisible && <HeavyComponent />}

// ✅ 用 CSS 隐藏(保持挂载状态)
<HeavyComponent style={{ display: isVisible ? 'block' : 'none' }} />

8. React 18 并发特性

// useTransition:将低优先级更新标记为可中断
const [isPending, startTransition] = useTransition()

const handleChange = (e) => {
  setInputValue(e.target.value) // 高优先级:立即更新输入框
  startTransition(() => {
    setSearchResults(search(e.target.value)) // 低优先级:可中断
  })
}

性能检测

同分类其他题目