Redux Toolkit状态无法更新求助:异步Thunk执行后状态未变更
Redux Toolkit状态无法更新问题
我是Redux Toolkit新手,尽管代码流程看似正确,但状态始终无法更新。以下是相关测试用例、被测代码及测试结果:
测试用例代码
import { ReduxStore } from '../../../react-view/main' import { configureStoreWith } from '../../../app/store' import { Dependencies } from '../../../app/dependencies' import { InMemoryIdProvider } from '../../../infrastructure/idProvider/InMemoryIdProvider' import { InMemoryRandomDiceProvider } from '../../../infrastructure/randomDiceProvider/InMemoryRandomDiceProvider' import { rollDice } from '../diceSlice' import { Die } from '../entities/Die' import { IdProvider } from '../ports/IdProvider' import { RandomDiceProvider } from '../ports/randomDiceProvider' function dieDataBuilder() { return new Die('uuid', { isHeld: false, value: 0, }) } describe('Generate Random Dice', () => { let store: ReduxStore let dependencies: Dependencies let idProvider: IdProvider let randomDiceProvider: RandomDiceProvider beforeEach(() => { idProvider = new InMemoryIdProvider() randomDiceProvider = new InMemoryRandomDiceProvider() dependencies = { idProvider: idProvider, randomDiceProvider: randomDiceProvider, } store = configureStoreWith(dependencies) }) it('should generate 10 random dice', () => { const expectedDice = Array(10).fill(dieDataBuilder()) store.dispatch(rollDice()) const generatedDice = store.getState().dice.dice expect(generatedDice).toStrictEqual(expectedDice) }) })
被测系统(SUT)代码
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' import { Dependencies } from '../../app/dependencies' import { Die } from './entities/Die' import { GenerateRandomDiceUseCase } from './usecases/GenerateRandomDiceUseCase' type ExtraDependencies = { extra: Dependencies } export const rollDice = createAsyncThunk<Die[], void, ExtraDependencies>( `dice/rollDice`, async (thunkAPI, { extra: { randomDiceProvider, idProvider } }) => { const dice = new GenerateRandomDiceUseCase( randomDiceProvider, idProvider, ).execute() return Promise.resolve(dice) }, ) export const initialState = { dice: [] as Die[], loading: false, error: null, } export const diceSlice = createSlice({ name: 'dice', initialState, reducers: {}, extraReducers: (builder) => { builder.addCase(rollDice.fulfilled, (state, action) => { console.log(action.payload) state.dice.concat(action.payload) return state }) }, })
控制台输出(action.payload内容)
[ Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } }, Die { id: 'uuid', props: { value: 0, isHeld: false } } ]
测试失败结果
Generate Random Dice ✕ should generate 10 random dice (109 ms) ● Generate Random Dice › should generate 10 random dice expect(received).toStrictEqual(expected) // deep equality - Expected - 72 + Received + 1 - Array [ - Die { - "id": "uuid", - "props": Object { - "isHeld": false, - "value": 0, - }, - }, [...], - Die { - "id": "uuid", - "props": Object { - "isHeld": false, - "value": 0, - }, - }, - ] + Array [] 38 | const generatedDice = store.getState().dice.dice 39 | > 40 | expect(generatedDice).toStrictEqual(expectedDice) | ^ 41 | }) 42 | }) 43 | at Object.<anonymous> (src/core/dice/usecases/GenerateRandomDice.spec.ts:40:27) Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 3.435 s, estimated 4 s Ran all test suites matching /src\/core\/dice\/usecases\/GenerateRandomDice.spec.ts/i. error Command failed with exit code 1.
问题原因及修复方案
1. Reducer中数组更新错误
concat方法会返回一个新数组,不会修改原数组state.dice,且手动返回state导致Immer无法追踪到状态变更。在Redux Toolkit的Immer环境中,可直接使用可变方法修改数组:
builder.addCase(rollDice.fulfilled, (state, action) => { console.log(action.payload) // 使用push批量添加元素,直接修改原数组 state.dice.push(...action.payload) // 无需return state,Immer会自动处理状态变更 })
或直接替换整个数组:
builder.addCase(rollDice.fulfilled, (state, action) => { console.log(action.payload) state.dice = action.payload })
2. 测试未等待异步Thunk完成
rollDice是异步Thunk,store.dispatch(rollDice())会返回Promise。测试中直接调用后立即获取状态时,Thunk尚未执行完成,状态未更新。需修改测试为异步函数并await dispatch:
it('should generate 10 random dice', async () => { const expectedDice = Array(10).fill(dieDataBuilder()) // 等待Thunk执行完成 await store.dispatch(rollDice()) const generatedDice = store.getState().dice.dice expect(generatedDice).toStrictEqual(expectedDice) })
修复以上两个问题后,测试即可正常通过,状态也会正确更新。
内容的提问来源于stack exchange,提问作者A Mehmeto
相关产品推荐
相关产品推荐

