React代码首次渲染正常,页面重渲染时崩溃的问题排查
问题:页面重渲染时筛选复选框功能崩溃,首次渲染正常
问题背景
基于以下筛选选项对象实现复选框筛选功能:
const filterOptions = { 'size': ['s', 'm', 'l'], 'color': ['black', 'white', 'pink', 'beige'], 'fit': ['relaxed fit','slim fit', 'skinny fit', 'oversize'], 'pattern': ['patterned', 'spotted', 'solid color'], 'material': ['wool', 'cotton', 'leather', 'denim', 'satin'] }
核心逻辑是通过checkedValue状态对象存储每个筛选值的选中状态,首次渲染时功能正常,但页面重渲染时抛出错误:
Uncaught TypeError: Cannot read properties of undefined (reading 'checked')
相关核心代码如下:
- 状态初始化与初始化逻辑:
const [checkedValue, setCheckedValue] = useState({}) useEffect(() => { const filterValuesArray = Object.values(filterOptions).flat() filterValuesArray.map(filter => setCheckedValue(currentState => ({...currentState, [filter]: { ...currentState[filter], checked: false }}))) }, [])
- 复选框渲染:
<div className='popper'> {filterValue.map(value => { return ( <div key={`${value}`} className='popper-item'> <label className='popper-label'>{value}</label> <input onChange={handleCheckbox} checked={checkedValue[value].checked} type='checkbox' value={value} className="popper-checkbox" /> </div> )} )} </div>
- 复选框 onChange 处理:
const handleCheckbox = (event) => { const value = event.target.value; setCheckedValue({...checkedValue, [value]: { ...checkedValue[value], checked: !checkedValue[value].checked }}) if(activeFilters.includes(value)) { const deleteFromArray = activeFilters.filter(item => item !== value) setActiveFilters(deleteFromArray) } else { setActiveFilters([...activeFilters, value]) }}
错误根源分析
- useEffect 依赖缺失:子组件中初始化
checkedValue的useEffect依赖为空数组,仅在组件首次挂载时执行。当页面重渲染(如父组件更新、Context状态变化)时,若checkedValue被重置或未包含当前筛选值,就会出现checkedValue[value]为undefined的情况,触发读取checked属性的错误。 - 状态更新未使用函数式更新:
handleCheckbox中直接依赖checkedValue的快照更新状态,React状态更新是异步的,多次快速操作可能导致状态不一致或丢失。 - 初始化逻辑低效:循环调用
setCheckedValue会触发多次状态更新,引发不必要的组件重渲染,也可能导致状态初始化不完整。
修复方案
1. 完善初始化逻辑与useEffect依赖
将filterOptions加入useEffect依赖,确保筛选选项变化时重新初始化;同时通过reduce一次性构建完整的初始化对象,避免多次状态更新:
useEffect(() => { const initialCheckedValue = Object.values(filterOptions).flat().reduce((acc, filter) => { acc[filter] = { checked: false }; return acc; }, {}); setCheckedValue(initialCheckedValue); }, [filterOptions, setCheckedValue]);
2. 使用函数式更新处理状态
在handleCheckbox中,使用函数式更新获取最新状态,避免异步更新导致的快照问题:
const handleCheckbox = (event) => { const value = event.target.value; // 函数式更新checkedValue setCheckedValue(prevState => ({ ...prevState, [value]: { ...prevState[value], checked: !prevState[value].checked } })); // 同样用函数式更新activeFilters setActiveFilters(prevFilters => { if (prevFilters.includes(value)) { return prevFilters.filter(item => item !== value); } else { return [...prevFilters, value]; } }); };
3. 添加可选链兜底(避免临时报错)
在渲染复选框时,使用可选链和空值合并运算符,确保即使checkedValue[value]不存在也不会报错:
<input onChange={handleCheckbox} checked={checkedValue[value]?.checked ?? false} type='checkbox' value={value} className="popper-checkbox" />
内容的提问来源于stack exchange,提问作者rey2197
相关产品推荐
相关产品推荐

