下面的代码,如果 count 连续发生两次变化,那么 loading 的状态就会被错误的提前设置为 false,怎么解决这个问题?
useEffect(() => { console.log("set loading: true"); setLoading(true); const ac = new AbortController(); new Promise<void>((resolve, reject) => { const timer = setTimeout(() => { console.log("resolve"); resolve(); }, 3000); ac.signal.addEventListener("abort", () => { clearTimeout(timer); reject("abrted"); }); }) .then(() => { setLazyCount(count); }) .catch((err) => { console.log("error:", err); }) .finally(() => { console.log("finally set loading: false"); setLoading(false); }); return () => { ac.abort(); console.log("abort"); }; }, [count]);
我尝试过把设置 loading 为true 的代码用 setTimeout 包裹起来,这样可以正确设置 loading,但是,当 Promise 立即完成的时候,顺序就又错误了。
useEffect(() => { setTimeout(() => { console.log("set loading: true"); setLoading(true); }); const ac = new AbortController(); new Promise<void>((resolve, reject) => { const timer = setTimeout(() => { console.log("resolve"); resolve();// ...
然后把这个部分全部放在 settimeout 中才可以,但是这样写也太别扭了
useEffect(() => { const ac = new AbortController(); setTimeout(() => { console.log("set loading: true"); setLoading(true); new Promise<void>((resolve, reject) => { const timer = setTimeout(() => { console.log("resolve"); resolve(); }, 3000); ac.signal.addEventListener("abort", () => { clearTimeout(timer); reject("abrted"); }); }) .then(() => { setLazyCount(count); }) .catch((err) => { console.log("error:", err); }) .finally(() => { console.log("finally set loading: false"); setLoading(false); }); }); return () => { ac.abort(); console.log("abort"); }; }, [count]);
在线测试 https://codesandbox.io/p/sandbox/use-effect-loading-fshhvm?fi...
useEffect(() => { let isActive = true; console.log("set loading: true"); setLoading(true); const ac = new AbortController(); new Promise<void>((resolve, reject) => { const timer = setTimeout(() => { console.log("resolve"); if (isActive) { resolve(); } }, 3000); ac.signal.addEventListener("abort", () => { clearTimeout(timer); if (isActive) { reject("aborted"); } }); }) .then(() => { if (isActive) { setLazyCount(count); } }) .catch((err) => { if (isActive) { console.log("error:", err); } }) .finally(() => { if (isActive) { console.log("finally set loading: false"); setLoading(false); } }); return () => { ac.abort(); isActive = false; console.log("abort"); };}, [count]);
在你的代码逻辑里看起来不应该直接用true或者false来判断。
这边提供一个思路:
应该设置一个全局变量 LoadingNum初始化为0,大于0的时候加载loading
你的代码里设置为true的时候执行LoadingNum++
你的代码里设置为false的时候执行LoadingNum--
这样可以避免应前一次结束影响下一次loading加载
这个问题是由于 React useEffect 的执行顺序导致的。当 count
连续发生两次变化时,由于 useEffect 的回调函数是在组件重新渲染时才执行,因此 setLoading(true)
会在两次连续的渲染之间设置 loading
为 true
。然后,当 Promise 立即完成时,setLoading(false)
会在 Promise 完成后立即执行,导致 loading
状态被错误地设置为 false
。
解决这个问题的一种方法是使用 useRef
钩子来存储上一个 Promise 是否已经完成的状态。在第一个 Promise 完成之后,将状态设置为 true
,然后在第二个 Promise 完成之后,将状态设置为 false
。这样就可以确保 loading
状态只在 Promise 完成之后被设置。
以下是修改后的代码:
import React, { useEffect, useRef, AbortController } from 'react';const App = () => { const countRef = useRef(0); const loadingRef = useRef(false); const [count, setCount] = React.useState(0); const [lazyCount, setLazyCount] = React.useState(0); const [loading, setLoading] = React.useState(false); useEffect(() => { const ac = new AbortController(); const handleLoad = () => { setLoading(true); new Promise<void>((resolve, reject) => { const timer = setTimeout(() => { console.log("resolve"); resolve(); }, 3000); ac.signal.addEventListener("abort", () => { clearTimeout(timer); reject("aborted"); }); }) .then(() => { setLazyCount(count); }) .catch((err) => { console.log("error:", err); }) .finally(() => { console.log("finally set loading: false"); setLoading(false); }); }; if (!loadingRef.current) { loadingRef.current = true; handleLoad(); } else { clearTimeout(handleLoad); // 如果在上一个 Promise 完成之前又触发了一次 render,那么取消这次的 load } return () => ac.abort(); }, [count]); return ( <div> Count: {count} <button onClick={() => setCount(count + 1)}>Increment</button> {loading && <div>Loading...</div>} {lazyCount && <div>Lazy Count: {lazyCount}</div>} </div> );};
1.手机翻转,或者折叠屏该怎么监听然后动态重新渲染echarts,需要加防抖或者节流吗? 2.横向条形图,左右两边的label怎么永远出现在可视范围内?比如148.00就已经飘出去了,看不全,还有左侧还有很多留白区域,不够美观 3.饼图中间的title的text和subtext能响应式的改变字体大小吗?像这种情况,字体完全超出了饼图范围
如图, 第一个表格是我自己写的css换行导致的,使用show-overflow="false"就好了。 第二个表格即使取消换行,使用省略号也会有错位的问题,拉到最后就会错位,想问一下怎么解决,谢谢!
如题。请大神指点
markdown图片可以传到本地文件夹但只能传jpg,png传不了,数据库也有路径,但是不渲染出来 头像上传七牛云,密钥和域名都写得对的但点击就报400
如果dev分支里面部分功能要上生产,该怎么做?比如dev里有ACD这四个功能,A还在测试,生产里有CD这几个功能,然后目前要上线B功能,该怎么把B功能合到生产分支里? 首先不能把dev全部合到生产分支,也不能把开发B功能的分支合到生产分支吧?因为开发B功能的分支是由dev拉出来的,也会有A功能的代码。
网址请求顺序是 souhu.com baidu.com tencent.com 这是什么原因呀?