是的,reducer 是同步运行的纯函数,因此任何单个调度的动作都会在下一个动作之前处理。
这可以帮助您更好地理解 reducer 函数:https ://redux.js.org/basics/data-flow
功能组件主体是完全同步的,所以一切都是按照每个渲染周期调用的顺序处理的。该链接来自redux,但reducer 的工作方式相同,并且可以互换,即reducer 函数具有签名(state, action) => nextState
。
所有钩子值都在渲染周期之间工作,这意味着,在渲染周期中“排队”的所有状态更新和分派动作都按该顺序进行批处理。
鉴于:
dispatch('a')
dispatch('b')
案例完成后,dispatch('b')
减速器案例将运行。 dispatch('a')
更新
useState
您可以查看和钩子的源代码,useReducer
看看它们将以相同的同步、顺序方式处理更新。
派遣
type Dispatch<A> = A => void;
在这里你可以看到这dispatch
是一个同步函数。
使用状态
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
使用减速器
export function useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const dispatcher = resolveDispatcher();
return dispatcher.useReducer(reducer, initialArg, init);
}
两者都useState
使用useReducer
相同的内部调度系统(即resolveDispatcher
)。由于useReducer
无法处理异步操作(例如 Redux-Thunks),因此没有其他选择,只能在处理下一个分派操作之前同步处理 reducer 中的操作。
更新 2
MODIFIED:那么 reducer 和 setStates 的组合呢?他们的通话顺序是否也保持不变?例如,一个 setState,一个 reducer(它使用 setState 中设置的状态的值)。
订单将保持不变,但您将无法将状态更新排入队列,然后根据更新后的状态调度操作。这是由于在渲染周期之间异步处理 React 状态更新的方式。换句话说,setState(newState)
直到下一个渲染周期之前都无法访问任何内容。
例子:
const [countA, setCountA] = useState(0);
const [countB, dispatch] = useReducer(.....);
...
setCountA(c => c + 1); // enqueues countA + 1, next countA is 1
dispatch(setCountB(countA)); // dispatches with countA === 0
setCountA(c => c + 1); // enqueues countA + 1, next countA is 2
dispatch(setCountB(countA)); // dispatches with countA === 0