У меня есть приложение React, которое управляет состоянием, используя контекст React. Я создал простое счетное воспроизведение с приращением .
Существует два контекста. Один для хранения состояния, а второй для отправки. Это шаблон, взятый из этой статьи .
Контекст состояния просто хранит одно число, и в этом состоянии можно вызвать только одно действие:
function reducer(state: State, action: Action): State {
switch (action.type) {
case "inc": {
return state + 1;
}
}
}
У меня также есть две вспомогательные функции для синхронного и асинхронного увеличения значения:
async function asyncInc(dispatch: React.Dispatch<Action>) {
await delay(1000);
dispatch({ type: "inc" });
dispatch({ type: "inc" });
}
function syncInc(dispatch: React.Dispatch<Action>) {
dispatch({ type: "inc" });
dispatch({ type: "inc" });
}
А вот как вы используете его в компоненте:
const counter = useCounterState();
const dispatch = useCounterDispatch();
return (
<React.Fragment>
<button onClick={() => asyncInc(dispatch)}>async increment</button>
<button onClick={() => syncInc(dispatch)}>sync increment</button>
<div>{counter}</div>
</React.Fragment>
);
Теперь, когда я нажимаю sync increment
кнопка все будет работать как положено. Он будет дважды вызывать операцию inc
, увеличивая счетчик на 2 и выполняя только одну повторную визуализацию компонента.
Когда я нажимаю кнопку async increment
, он сначала ждет одну секунду и выполняет операцию inc
дважды, но он будет перерисовывать компонент дважды.
Вы должны открыть консоль, чтобы увидеть журналы от компонентов рендеринга.
Я вроде понимаю, почему это так. Когда это синхронная операция, все происходит во время рендеринга компонента, поэтому он сначала манипулирует состоянием и рендерит в конце. Когда это асинхронная операция, она сначала выполняет рендеринг компонента, а через одну секунду она обновляет состояние после запуска повторного рендеринга и обновляет во второй раз, вызывая следующий повторный рендеринг.
Таким образом, можно выполнить асинхронное обновление состояния, выполнивтолько один повтор? В том же воспроизведении есть похожий пример, но с использованием React.useState, у которого тоже есть та же проблема.
Может, мы как-то будем пакетно обновлять? Или мне нужно создать другое действие, которое бы одновременно выполняло несколько операций над состоянием?
Я также создал это воспроизведение , которое решает эту проблему, выполняя множество действий, но яЛюбопытно, можно ли этого избежать.