React中Redux Dispatch函数搭配Async/Await失效问题排查
问题原因及解决办法
你这里的await dispatch(login(values))其实是生效的,它确实会等待login异步thunk执行完成,但console.log(success)打印的是旧值,核心原因是闭包捕获的状态快照问题:
- 组件渲染时,
useSelector获取到的success是当前Redux状态的快照,这个值被捕获到了onSubmit函数的闭包里。 - 当异步thunk执行完成,Redux状态更新(
success变为true),但此时当前的onSubmit函数还是拿着之前捕获的旧success值——组件要等到状态更新后重新渲染,才会拿到新的success,而当前的console.log是在重新渲染前执行的,所以看不到更新后的值。
解决办法
方法1:用useEffect监听success的变化
如果你的逻辑是要在success变为true时执行后续操作,直接监听这个状态更可靠:
const { success, loading, error } = useSelector((state) => state.loginReducer); useEffect(() => { if (success) { console.log(success); // 这里会拿到更新后的值 // 执行你的后续逻辑,比如跳转页面等 } }, [success]); const formik = useFormik({ initialValues, validationSchema, onSubmit: async (values) => { await dispatch(login(values)); // 这里不要再依赖success,交给useEffect处理 }, });
方法2:用unwrapResult获取thunk的返回结果
Redux Toolkit的createAsyncThunk支持用unwrapResult来获取异步操作的返回值(或者捕获错误),这样你可以直接拿到thunk执行后的结果,不需要依赖组件的状态:
import { unwrapResult } from '@reduxjs/toolkit'; // ... const formik = useFormik({ initialValues, validationSchema, onSubmit: async (values) => { try { const result = await unwrapResult(dispatch(login(values))); // 这里thunk已经执行完成,Redux状态也更新了 console.log('登录成功', result); } catch (err) { console.log('登录失败', err); } }, });
方法3:在dispatch后手动获取最新状态(不推荐)
可以用useStore获取store实例,然后调用getState拿到最新状态,但这种方式绕过了React的状态更新机制,不太推荐:
import { useStore } from 'react-redux'; // ... const store = useStore(); const formik = useFormik({ initialValues, validationSchema, onSubmit: async (values) => { await dispatch(login(values)); const latestSuccess = store.getState().loginReducer.success; console.log(latestSuccess); // 这里会拿到更新后的值 }, });
内容的提问来源于stack exchange,提问作者khaled saeed
相关产品推荐
相关产品推荐

