reactjs - 调度在 UseEffect 内与 Async 函数一起触发
问题描述
有一个 Profile 组件可以使用异步函数创建 3D 面部。为了通知用户等待,在UseEffect中的繁重任务之前和之后触发了两次调度。问题是这两个派发的只有在繁重的任务完成后才开火。
Profile.js
const Profile = (props) => {
const [face3D, setFace3D] = useState(null)
const { state, dispatch } = useContext(UserContext)
const drawFace = async () => {
// a heavy calculation
}
useEffect(() => {
// show user loading
dispatch({
type: "USER_LOADING",
payload: true
})
drawFace().then( face => {
setFace3D(face)
// clear user loading
dispatch({
type: "USER_LOADING",
payload: false
})
})
}, [props.data])
return (
<Canvas>
{ face3D }
</Canvas>
)
}
export default Profile
UserContext.js
import React, { createContext, useReducer } from 'react'
import { createReducer } from 'react-use'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
export const UserContext = createContext()
const useThunkReducer = createReducer(thunk, logger);
const UserContextProvider = (props) => {
const initialState = {
loading: false
}
const [state, dispatch] = useThunkReducer(UserReducer, initialState)
return (
<UserContext.Provider value={{ state, dispatch }}>
{ props.children }
</UserContext.Provider>
)
}
export default UserContextProvider
PS:redux-logger显示了正确的dispatch顺序,即使记录reducer显示将状态更改为true并最终更改为false但状态仅反映最后一次调度(类似于突变状态的情况,但未突变)
解决方案
因为您已经注意到这drawFace
是一个“繁重的计算”,所以我怀疑它实际上并不是异步的。我认为正在发生的是:
- 第一个
dispatch
叫做 - 执行 drawFace 并计算其返回值。因为函数是
async
,所以结果被包装在一个 Promise 中。 .then()
向事件循环添加一个任务,该任务调用setFace3D
和第二次调用dispatch
.
超时后尝试调用drawFace:
dispatch(...)
setTimeout(() => {
drawFace().then(face => {
setFace3D(face);
dispatch(...)
})
}, 0)
标记函数async
不会自动在后台线程或类似的东西上运行函数体。相反,它做了两件事:
- 允许使用
await
关键字 - 自动将返回的值(或抛出的错误)包装在 Promise 中。
请注意,在以下示例中,“calculate”记录在“after call calculate”之前,即使该函数标记为async
。
async function calculate() {
console.log("calculate")
}
console.log("before calling calculate")
calculate().then(() => {
console.log("calculation done")
})
console.log("after calling calculate")
// Result:
// "before calling calculate"
// "calculate"
// "after calling calculate"
// "calculation done"
推荐阅读
- c++ - 奇怪的 C++ 错误,不合格的 ID,重新声明
- r - ggplot 多个箱线图和 stat_summary 位置
- python - python数据框中的超链接字符串
- coq - 代数表达式的基本操作
- python-3.x - 执行许多获取请求
- arrays - 如何在laravel的foreach循环中传递多个变量
- c# - 将 Xamarin 位图转换为 byte[] 不起作用或抛出异常
- ios - UIBackgroundRefreshStatusDenied 未发送静默推送通知,但应用程序在前台
- java - Java - 获取路径中层次结构中的最后一个目录
- html - 图像顶部的移动按钮