关于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.
相关产品推荐
相关产品推荐

