如何修复React警告:无法对已卸载的组件执行状态更新
问题根因
你遇到的警告核心是两个问题共同导致的:
- 列表渲染的
key使用了索引index,当你修改药物数据触发父组件重渲染时,React会错误卸载对应位置的Medication组件,此时你再调用setOpenUpdate(false)就会触发已卸载组件的状态更新警告。 updateDose函数中直接修改了原数组,违反了React状态更新的不可变原则,也会导致组件渲染逻辑异常。
修复步骤
1. 替换列表渲染的key为唯一标识
将父组件中渲染药物列表的逻辑修改为使用药物id作为key,不要使用索引:
const medications = parsed.map((medication) => { return (<Medication medication={medication} key={medication.id}/>) });
2. 修正updateDose的数组修改逻辑,遵循不可变原则
不要直接修改原数组的元素,改为生成新数组后存入localStorage:
// 更新剂量按钮的触发函数 function updateDose(medicationId, parsedMedications, data) { // 生成新数组,不修改原数组避免渲染异常 const newParsedMedications = parsedMedications.map(item => item.id === medicationId ? {...item, dose: data.dose} : item ) localStorage.setItem("medications", JSON.stringify(newParsedMedications)); // 关闭弹窗 setOpenUpdate(false); }
3. 补充挂载状态判断(可选,解决弹窗过渡动画导致的警告)
如果修改后仍有警告,可在Medication组件中添加挂载状态标记,避免组件卸载后执行状态更新:
const Medication = ({medication}) => { const {handleSubmit, control, formState} = useForm({ mode: "onChange", resolver: yupResolver(validationSchema) }); // 用于控制更新药物弹窗的显示隐藏 const [openUpdate, setOpenUpdate] = useState(false); // 挂载状态标记 const isMounted = useRef(true); useEffect(() => { // 组件卸载时修改标记 return () => { isMounted.current = false; } }, []) const handleClickOpenUpdate = () => { setOpenUpdate(true); }; const handleCloseUpdate = () => { if(isMounted.current) { setOpenUpdate(false); } }; // 其余代码不变... function updateDose(medicationId, parsedMedications, data) { const newParsedMedications = parsedMedications.map(item => item.id === medicationId ? {...item, dose: data.dose} : item ) localStorage.setItem("medications", JSON.stringify(newParsedMedications)); if(isMounted.current) { setOpenUpdate(false); } } // 其余代码不变... }
内容的提问来源于stack exchange,提问作者Valerie Hosler
相关产品推荐
相关产品推荐

