使用Promise的useEffect正确清理方法,解决组件卸载更新状态警告
解决方案
你可以通过以下两种方式实现清理逻辑,避免该警告:
方案1:挂载状态标志位(快速实现)
在useEffect内部声明一个标志位记录组件是否仍处于挂载状态,所有状态更新操作执行前先校验该标志位:
useEffect(() => { // 标记组件是否挂载 let isMounted = true; const fetchAllData = async () => { const resourceOne = new Promise((resolve) => { // 拉取资源1的逻辑 fetch('/api/resource1') .then(res => res.json()) .then(data => { // 仅挂载状态下更新状态 if (isMounted) { // 这里更新对应state } resolve(); }) }) const resourceTwo = new Promise((resolve) => { // 拉取资源2的逻辑 fetch('/api/resource2') .then(res => res.json()) .then(data => { if (isMounted) { // 这里更新对应state } resolve(); }) }) const resourceThree = new Promise((resolve) => { // 拉取资源3的逻辑 fetch('/api/resource3') .then(res => res.json()) .then(data => { if (isMounted) { // 这里更新对应state } resolve(); }) }) await Promise.all([resourceOne, resourceTwo, resourceThree]) .then(() => { if (isMounted) { // 全部拉取完成后更新状态 } }) } fetchAllData(); // 清理函数,组件卸载时修改标志位 return () => { isMounted = false; } },[])
这个方案实现简单,能快速解决警告问题,但缺点是不会终止实际的网络请求,仅会跳过卸载后的状态更新操作。
方案2:使用AbortController终止请求(更推荐)
如果使用的是fetch、axios等支持中断请求的请求库,可以用AbortController在组件卸载时直接取消未完成的请求,从根源避免后续的状态更新逻辑执行,还能节省不必要的网络资源消耗:
useEffect(() => { // 声明中断控制器 const controller = new AbortController(); const signal = controller.signal; const fetchAllData = async () => { try { const resourceOne = new Promise((resolve) => { // 绑定signal到请求中 fetch('/api/resource1', { signal }) .then(res => res.json()) .then(data => { // 此处不需要额外判断,请求被中断会直接进入catch // 更新对应state resolve(); }) }) const resourceTwo = new Promise((resolve) => { fetch('/api/resource2', { signal }) .then(res => res.json()) .then(data => { // 更新对应state resolve(); }) }) const resourceThree = new Promise((resolve) => { fetch('/api/resource3', { signal }) .then(res => res.json()) .then(data => { // 更新对应state resolve(); }) }) await Promise.all([resourceOne, resourceTwo, resourceThree]) .then(() => { // 全部拉取完成后更新状态 }) } catch (err) { // 忽略请求中断的错误 if (err.name !== 'AbortError') { console.error('请求出错:', err); } } } fetchAllData(); // 清理函数,组件卸载时中断所有未完成的请求 return () => { controller.abort(); } },[])
注:如果使用axios等其他请求库,对应中断请求的API可能略有不同,参考对应库的文档绑定取消信号即可。
内容的提问来源于stack exchange,提问作者Romanas
相关产品推荐
相关产品推荐

