React修改Set类型state后组件未触发重渲染问题排查
问题原因
React 触发重渲染的前提是检测到 state 引用发生变化,内部对 state 做浅比较判断是否需要更新。
当前代码存在两个违反状态不可变原则的问题:
let newSet = activeItems仅拷贝了原 Set 的引用,没有创建新的 Set 实例,后续调用add()/delete()都是直接修改原始 state 对象setActiveItems最终传回的还是和原 state 指向同一块内存的 Set 对象,React 浅比较判定 state 未发生变化,直接跳过重渲染流程,只有组件重新挂载时才会读取最新的 state 值展示。
修复方法
更新状态时基于原 state 创建全新的 Set 实例,在新实例上做增删操作,保证传回 setState 的是新的引用:
export const InterestsPupup: React.FC = ({interests, title, buttonText}) => { const [activeItems, setActiveItems] = useState(new Set()) const clickOnItemHandler = (item: string) => { setActiveItems(prev => { // 基于原有Set值创建新实例,生成全新引用 const newSet = new Set(prev) newSet.has(item) ? newSet.delete(item) : newSet.add(item) return newSet }) } return ( <div className={styles.Container__main}> {interests.map((item , index) => { return ( <div key={index} className={activeItems.has(item) ? clsx(styles.item, styles.item_active) : styles.item} onClick={() => clickOnItemHandler(item)} >{item}</div> ) })} </div> ); };
注意:所有引用类型(Object、Array、Map、Set)作为 state 存储时,都必须遵守不可变更新规则,不能直接修改原对象,要在新的副本上做修改后再传给 setState,否则会出现状态更新但不重渲染的问题。
内容的提问来源于stack exchange,提问作者bluepuper
相关产品推荐
相关产品推荐

