Начиная с React 18, обновления состояния автоматически группируются . При использовании Redux также используются батчи. Однако, похоже, это не работает при использовании асинхронных вызовов. Например, для thunk:
const incrementAsync = createAsyncThunk("incrementAsync", (_, { dispatch }) => {
setTimeout(() => {
dispatch(increment());
}, 1000);
});
Следующее заставит компонент перерендериться три раза (но визуально счетчик изменится только один раз):
const increment = () => {
dispatch(incrementAsync());
dispatch(incrementAsync());
dispatch(incrementAsync());
};
Я не знаю, является ли это ожидаемым поведением, но как мне сделать так, чтобы эти обновления были пакетными? Я хотел бы, чтобы мой компонент перерисовывался только один раз, независимо от количества обновлений.
Обратите внимание:
Я сделал эти фрагменты только для вопроса, мой код не имеет ничего общего с простыми счетчиками, и мне нужно, чтобы вызовы были асинхронными.
🤔 А знаете ли вы, что...
JavaScript был первоначально создан для улучшения интерактивности веб-страниц.
@reduxjs/инструментарий: ^ 1.9.5
Вы можете использовать autoBatchEnhancer
Улучшитель хранилища Redux, который ищет одно или несколько отправленных действий с «низким приоритетом» подряд и ставит в очередь обратный вызов для запуска уведомлений подписчика с задержкой. Затем он уведомляет подписчиков либо о выполнении обратного вызова в очереди, либо об отправке следующего действия с «нормальным приоритетом», в зависимости от того, что произойдет раньше.
counterSlice.js
:
import { createSlice, createAsyncThunk, prepareAutoBatched, SHOULD_AUTOBATCH } from '@reduxjs/toolkit';
export const incrementAsync = createAsyncThunk('incrementAsync', (_, { dispatch }) => {
setTimeout(() => {
dispatch(increment());
}, 1000);
});
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: {
reducer: (state, action) => {
console.info('action: ', action);
state.value += 1;
},
prepare: prepareAutoBatched(),
},
}
});
export const { increment } = counterSlice.actions;
export const selectCount = (state) => state.counter.value;
export default counterSlice.reducer;
store.js
:
import { configureStore, autoBatchEnhancer } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export default configureStore({
reducer: {
counter: counterReducer,
},
enhancers: (existingEnhancers) => {
// Add the autobatch enhancer to the store setup
return existingEnhancers.concat(autoBatchEnhancer());
},
});