React父组件更新状态时子Radio组件不必要重渲染问题排查
你的实现里有几个关键问题导致React.memo优化失效,同时引发不必要重渲染:
1. 动态生成的key导致组件强制重建
你给map循环的容器div用了key={${item.id + Math.random()}},每次父组件渲染时Math.random()都会生成新值,React会把每个Radio容器判定为全新组件,直接卸载旧组件并创建新实例,完全跳过React.memo的浅比较优化。
解决方法:
直接用item.id作为key(确保item.id是唯一且稳定的标识):
<div className={styles.search_box_row_one_radio_box} key={item.id}>
2. 回调函数每次渲染都重新创建
父组件中的handleSectionChange是内联函数,每次父组件状态更新(比如调用setSelectedSectionValue)都会重新生成这个函数的新引用。React.memo默认对props做浅比较,onChange引用变化会触发Radio组件重渲染。
解决方法:
用useCallback包裹回调函数,缓存函数引用,只有依赖项变化时才重新生成:
import { useCallback } from 'react'; const handleSectionChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { setSelectedSectionValue(event.target.value); }, []); // 依赖为空,因为setSelectedSectionValue是React状态更新函数,本身稳定
3. 使用defaultChecked导致非受控组件问题
你当前用defaultChecked设置初始选中状态,但父组件维护了selectedSectionValue状态,这会导致组件变成半受控状态:状态更新后,Radio的选中状态不会和父组件同步,同时也会干扰React的渲染逻辑。
解决方法:
改成受控组件,用checked属性绑定父组件状态,替代defaultChecked:
- 子组件Radio接收
checked属性:
import { memo } from 'react'; import { RadioButtonConfig } from '../../../models/radio'; export const Radio = memo(({ onChange, className, id, value, name, label, checked} : RadioButtonConfig) => { return ( <div className={className}> <input type="radio" id={id} value={value} name={name} onChange={onChange} checked={checked} // 替换defaultChecked为checked /> <label htmlFor={id} > {label}</label > </div > ); });
- 父组件传入checked属性,对比当前item.value和选中状态:
<Radio label={item.label} className={styles.search_box_row_one_radio} id={item.id} value={item.value} name={item.name} onChange={handleSectionChange} checked={item.value === selectedSectionValue} // 绑定父组件状态 />
4. 确保React.memo正确生效
修复上述问题后,给Radio组件包裹React.memo(如上代码所示),此时React会对组件props做浅比较,只有当props真正变化时才触发重渲染。
这样修改后,就能彻底解决Radio组件不必要重渲染的问题。
内容的提问来源于stack exchange,提问作者sooraj s pillai

