这是因为 React 不依赖于这样的异步任务,有两种方法可以模拟你想要的结果。一个我称之为标准版本,一个不稳定版本。
不稳定版本
第一种方法是将更新包装在 unstable_batchedUpdates 回调中。顾名思义,此 API 将在一次对账过程中批量更新您的更新,从而减少组件渲染。
所以更新后的代码会是这样的:
import { unstable_batchedUpdates } from "react-dom";
const updateMyBiddingList = async (atDate?: string) => {
try {
console.log('step 0');
const result = await getBiddingCartFromService(atDate ? atDate : myBiddingListState.myBiddingList[0].updatedAt);
// Add unstable API where you cause re-render ⭐
unstable_batchedUpdates(() => {
if (result.responseCode.toString().startsWith('2')) {
setAAA(true);
console.log('step 1');
}
console.log('step 2 ', aaa);
})
}
catch (err) {
if (timeOut.current) clearTimeout(timeOut.current);
timeOut.current = setTimeout(() => updateMyBiddingList(), TIMEOUT);
}
}
这会将日志的顺序更改为此
Component is re-rendering... false
step 0
step 1
step 2 false
Component is re-rendering... true
您可以在以下代码沙箱中看到使用来自 JSON 占位符的假数据运行的代码。
标准版(react common 模式)
这不是你可以做你想做的唯一模式,但它对我来说似乎更像是反应式的:)
- 您正在请求(异步操作)
- 您想要更改将导致重新渲染的组件状态
此阶段还会更改下一次渲染的函数定义
我坚持您的实现,不想将 useEffect 部分拆分为可重复使用的小部分,尽管您可能想考虑一下。
解决方案是将你的逻辑移到它所属的地方,这意味着你将在你的 dom 树中调用该函数调用。
// instead of aaa and setAAA :)
const [updated, setUpdated] = useState<boolean>(false)
const [hasError, setHasError] = useState<boolean>(false)
const timeOut = useRef<number>()
useEffect(() => {
const updateMyBiddingList = async (atDate?: string) => {
try {
console.log('step 0');
const result = await getBiddingCartFromService(atDate ? atDate : myBiddingListState.myBiddingList[0].updatedAt);
setHasError(false)
if (result.responseCode.toString().startsWith('2')) {
setUpdated(true);
console.log('step 1');
}
console.log('step 2 ', updated);
}
catch (err) {
setHasError(true)
if (timeOut.current) clearTimeout(timeOut.current);
timeOut.current = setTimeout(() => updateMyBiddingList(), TIMEOUT);
}
}
if (!updated || hasError) updateMyBiddingList()
// timeOut.current can also be added here but it is not recommended
}, [updated, hasError])