为什么React函数组件仅首次触发未挂载组件状态更新警告
触发警告的根本原因
你写的规避逻辑本身存在缺陷:props.enable的判断放在了setTimeout的注册环节,取的是点击子组件按钮瞬间的prop值,此时子组件还处于挂载状态,props.enable必然为true,所以定时器一定会被注册,和后续组件是否卸载完全无关。
仅首次触发警告的原因
- 首次操作严格按照复现步骤执行:点击子组件按钮后立刻点击父组件卸载按钮,1秒后定时器回调触发,此时组件已经卸载,调用
setState直接触发警告。 - 后续操作时,你大概率会先等待前一次的定时器执行完成,再重新挂载子组件做测试:如果点击子组件按钮后间隔超过1秒再卸载组件,定时器回调已经执行完毕,自然不会触发警告。如果严格按照首次的操作节奏,每次点击子组件按钮后立刻卸载,后续同样会触发警告。
正确的规避方案
两种标准写法可以彻底解决这个警告:
方案1:定时器回调内判断组件挂载状态
import React, { useState, useEffect, useRef } from "react"; export const Test = (props) => { const [state, setstate] = useState(false); // 标记组件挂载状态 const isMounted = useRef(true); useEffect(() => { // 卸载时更新标记 return () => { isMounted.current = false; }; }, []); const fetchData = () => { setstate(!state); setTimeout(() => { // 回调执行时先判断组件是否还挂载 if (isMounted.current) { setstate(false); } }, 1000); }; return ( <> <button onClick={fetchData}> {`${state}`}</button> </> ); };
方案2:组件卸载时直接清除定时器
import React, { useState, useEffect } from "react"; export const Test = (props) => { const [state, setstate] = useState(false); let timer = null; useEffect(() => { // 卸载时清除未执行的定时器 return () => { if (timer) clearTimeout(timer); }; }, []); const fetchData = () => { setstate(!state); timer = setTimeout(() => { setstate(false); }, 1000); }; return ( <> <button onClick={fetchData}> {`${state}`}</button> </> ); };
内容的提问来源于stack exchange,提问作者harshilparmar
相关产品推荐
相关产品推荐

