【发布时间】:2021-03-12 08:51:34
【问题描述】:
我有两个动作 TEST 和 TEST_DONE 在我的 redux 状态下都增加了一个 id 属性。每当我从我的组件调度第一个动作 TEST 时,我都会使用 redux-saga 自动调度第二个动作 TEST_DONE。
我希望执行顺序是这样的:
- 组件渲染初始值为
testState.id=0 - 组件调度
TEST动作 - 组件重新渲染
testState.id=1 - saga 调度
TEST_DONE操作 - 组件重新渲染
testState.id=2
相反,我的组件仅在 testState.id 更新为 2 时重新渲染。我在getSnapshotBeforeUpdate 函数中看不到1 值。它将0 显示为前一个属性。
为什么 prop 从 0 跳转到 2 中间没有收到 1?
saga.js:
export function* TestSagaFunc() {
yield put({
type: actions.TEST_DONE
});
};
export default function* rootSaga() {
yield all([
yield takeEvery(actions.TEST, TestSagaFunc),
]);
};
action.js:
const actions = {
TEST: 'TEST',
TEST_DONE: 'TEST_DONE',
callTest: (id) => ({
type: actions.TEST,
payload: {
id
}
}),
};
export default actions;
reducer.js:
const initState = {
testState: {
id: 0
}
};
export default function TestReducers ( state=initState, { type, ...action}) {
switch(type) {
default:
return state;
case actions.TEST: {
const { id } = state.testState;
const nextId = id + 1;
return {
...state,
testState: {
...state.testState,
id: nextId
}
};
};
case actions.TEST_DONE: {
const { id } = state.testState;
const nextId = id + 1;
return {
...state,
testState: {
...state.testState,
id: nextId
}
};
}
};
};
组件getSnapshotBeforeUpdate的控制台输出
【问题讨论】:
-
如您所见,状态确实在更新,但组件渲染并不能保证在每次状态更改时都会发生。尝试从
redux-saga/effects和yield delay(1000);导入delay,然后再在TestSagaFunc中调用yield put,这样两个状态更新就不会一起批处理。 -
@azundo 感谢您的回复,您是对的。我尝试按照您所说的进行导入,但我认为这只是一个技巧。你还有什么要彻底处理的吗?
-
是的,这只是一个技巧。如果您需要渲染中间状态,您可以使用
useEffect(或componentDidUpdate)从正在渲染的组件中分派您的第二个操作,以确保组件通过一个更新状态的渲染周期。但是没有办法强制你的组件渲染中间减速器状态,这些状态在渲染周期之间更新。 -
那是我对 redux-saga 的了解不足。传奇帮助我们处理副作用,但我的测试不是。您分享的信息非常有帮助,我解决了我的问题。非常感谢@azundo
-
@azundo 我必须阅读这个问题和你的评论几次才能明白你在说什么。我的第一个想法是“当 redux 状态发生变化时,组件肯定会重新渲染”。但是我在这里看到我们正在谈论立即覆盖的中间更改。所以这归结为 React 如何批量更新,这不是我理解的深入到无法解释的内容。