在Rematch中如何在异步操作后更新状态并触发副作用?
我在用Rematch处理登录流程时遇到问题:调用API后需要先更新用户状态,再根据角色信息触发权限检查的副作用。但发现第二个effect总是获取到旧的user状态,代码该怎么改?
尝试过这样写:
export const handleLogin = ({ dispatch, payload }) => {
api.login(payload).then(user => {
dispatch(user.set(user)); // 第一个dispatch
dispatch(role.checkRole()); // 立即调用第二个effect
});
};
但第二个effect里的state.user始终是未登录状态,看起来dispatch不是同步更新的。如果把checkRole放在.then后会不会更可靠?或者需要怎么保证状态更新顺序?
dispatch(user.set(user))后,紧接着调用dispatch(role.checkRole()),这时候状态可能还没真正更新完成,导致第二个effect拿到的还是旧的状态。这是一个常见的坑。要解决这个问题,你可以利用Rematch的effects特性,把第二个操作放在第一个状态更新完成后再触发。常见的解决方案是改写成这样的结构:
这里的关键点是,
dispatch.user.set(user)返回的是一个Promise,等这个Promise resolve后,状态就已经更新完成了。接着你再调用dispatch.role.checkRole()就能拿到最新的state。如果你觉得链式调用不够直观,也可以用async/await来写,逻辑更清晰一些:
这两种方式都能保证状态更新的顺序性。我个人更喜欢用async/await,因为代码读起来更线性,不容易出错。不过无论哪种写法,核心思想都是:确保第一个状态更新完成后再触发依赖它的副作用。
对了,顺便提一句,记得检查你的
checkRole方法是不是正确订阅了state变化,有时候问题也可能出在订阅逻辑上。你可以这样改:
export const handleLogin = ({ dispatch, payload }) => {
api.login(payload).then(user => {
return dispatch(user.set(user)).then(() => {
dispatch(role.checkRole());
});
});
};
或者用async/await更清晰:
export const handleLogin = async ({ dispatch, payload }) => {
const user = await api.login(payload);
await dispatch(user.set(user));
dispatch(role.checkRole());
};
关键点在于,dispatch返回的是一个Promise,只有await或.then之后才能确保state已经更新完毕。这样第二个effect拿到的就是最新的user状态了。
前端这种异步流程就得靠Promise链或者async/await来控制执行顺序,JS里面没有银弹,只能老老实实用Promise把顺序锁死。