You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于React Memo的疑问:按钮点击引发不必要重渲染问题

React组件不必要重渲染的解决方法

我正在学习React,目前实现了多个组件化按钮。点击其中一个按钮时,包括父组件在内的其他按钮组件也会被重新渲染。相关代码如下:

import { useState } from 'react'

const Button = ({ setState, text }) => {

  console.log(`${text} rendering`)

  return (<button
    onClick={e => setState(prevState => !prevState)}
  >
    {text}
  </button>)
}

const Page = () => {

  console.log('Page rendering')

  const [aaa, setAaa] = useState(false)
  const [bbb, setBbb] = useState(false)

  return (<>

    <div>
      <Button
        setState={setAaa}
        text="A button"
      />
      <pre>{JSON.stringify(aaa, null, 2)}</pre>
    </div>

    <div>
      <Button
        setState={setBbb}
        text="B button"
      />
      <pre>{JSON.stringify(bbb, null, 2)}</pre>
    </div>

  </>)
}

export default Page

以下是具体的解决办法:

方法1:用React.memo优化子组件

React.memo会对组件接收的props做浅比较,只有当props真正变化时才触发组件重渲染。你的Button组件接收的setState(useState返回的更新函数是稳定引用)和text都是固定值,所以用React.memo包裹即可阻止不必要的重渲染:

import { useState, memo } from 'react'

// 用memo包裹Button组件
const Button = memo(({ setState, text }) => {
  console.log(`${text} rendering`)
  return (
    <button onClick={() => setState(prev => !prev)}>
      {text}
    </button>
  )
})

const Page = () => {
  console.log('Page rendering')
  const [aaa, setAaa] = useState(false)
  const [bbb, setBbb] = useState(false)

  return (
    <>
      <div>
        <Button setState={setAaa} text="A button" />
        <pre>{JSON.stringify(aaa, null, 2)}</pre>
      </div>
      <div>
        <Button setState={setBbb} text="B button" />
        <pre>{JSON.stringify(bbb, null, 2)}</pre>
      </div>
    </>
  )
}

export default Page

修改后点击A按钮,只有Page和A按钮会重渲染,B按钮不会触发渲染日志。

方法2:拆分组件隔离状态

把每个按钮和对应的状态展示拆成独立组件,让每个组件只管理自身状态,这样单个组件的状态变化不会影响其他组件:

import { useState } from 'react'

const ButtonGroup = ({ text, initialState }) => {
  console.log(`${text} group rendering`)
  const [state, setState] = useState(initialState)
  
  return (
    <div>
      <button onClick={() => setState(prev => !prev)}>
        {text}
      </button>
      <pre>{JSON.stringify(state, null, 2)}</pre>
    </div>
  )
}

const Page = () => {
  console.log('Page rendering')

  return (
    <>
      <ButtonGroup text="A button" initialState={false} />
      <ButtonGroup text="B button" initialState={false} />
    </>
  )
}

export default Page

这种方式下,点击A按钮只会触发A对应的ButtonGroup重渲染,父组件和B的组件都不会受到影响。

注意事项

  • 第一种方法中,父组件Page的重渲染是必要的,因为它需要展示状态值,状态变化时必须更新DOM。但通过React.memo可以避免无关子组件的冗余渲染。
  • 如果后续Button需要接收对象、数组这类复杂props,要配合useCallback或useMemo保证props的引用稳定,否则React.memo会失效。

内容的提问来源于stack exchange,提问作者i'm fat.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:30:48