如何解决调用useState的set函数后React组件重渲染问题?
问题原因
当你调用setStopChange(true)或setStopChange(false)时,本质是在更新组件的stopChange状态。React的核心机制就是:组件的状态(state)发生变更时,会触发组件的重渲染,以此保证UI和状态同步。这就是你在Chrome React Profiler里看到重渲染的根本原因。
而当你把onMouseEnter和onMouseLeave设为空函数时,这些函数不会修改任何状态,组件的state没有变化,自然不会触发重渲染。
解决方法
如果你的需求是保留鼠标事件功能,同时想优化不必要的重渲染(比如避免事件函数引用频繁变化导致的额外开销),可以参考以下方案:
1. 用useCallback缓存事件处理函数
useCallback可以固定函数的引用,避免每次组件重渲染时创建新的函数实例。如果后续给子组件传递这些函数,配合React.memo包裹子组件,就能避免子组件因为函数引用变化而重复渲染:
import { useState, useCallback } from 'react'; import s from './Pizza.module.scss'; const Pizza = () => { const [stopChange, setStopChange] = useState(false); console.log('rerender'); // 缓存事件函数 const handleMouseEnter = useCallback(() => { setStopChange(true); }, []); const handleMouseLeave = useCallback(() => { setStopChange(false); }, []); return ( <> <div className={s.wrapper} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} > <div className={s.container}> </div> </div> <div className={s.box}> </div> </> ); } export default Pizza;
2. 用useRef替代useState(特殊场景)
如果你的业务逻辑里,更新stopChange后不需要同步UI(这种场景很少见),可以用useRef替代useState——它的变更不会触发组件重渲染:
import { useRef } from 'react'; import s from './Pizza.module.scss'; const Pizza = () => { const stopChangeRef = useRef(false); console.log('rerender'); return ( <> <div className={s.wrapper} onMouseEnter={() => stopChangeRef.current = true} onMouseLeave={() => stopChangeRef.current = false} > <div className={s.container}> </div> </div> <div className={s.box}> </div> </> ); } export default Pizza;
3. 接受正常重渲染(多数场景无需优化)
如果你的组件本身逻辑简单,重渲染的性能开销可以忽略不计,完全可以接受这种正常的重渲染——React对重渲染做了大量优化,简单组件的重渲染几乎不会影响性能。
内容的提问来源于stack exchange,提问作者Florkir
相关产品推荐
相关产品推荐

