React/Redux Toolkit:createAsyncThunk返回数据后如何同步更新组件状态
Redux Toolkit环境下账户更新后状态不同步的问题解决
实际开发场景
开发中编写了用于更新数据库账户数据的异步请求,接口成功返回最新的账户结构化数据,返回结构示例:
{ "Nome": "a", "Valor": 1700, "Historico": "teste", "Documento": 1, "DataEmissao": "2020-12-24T00:00:00.000Z", "DataVencimento": "2020-12-24T00:00:00.000Z", "createdAt": "2021-03-30T14:13:31.404Z", "id": "6063320bafd21c22e45f404c", "updatedAt": "2021-03-31T14:56:43.873Z", "__v": 0 }
存在的异常表现:
- 接口请求完成后,Redux Store与关联组件不会用最新返回的数据覆盖旧值
- 只有手动刷新页面、重新从数据库全量拉取列表数据时,页面才能显示最新的账户信息
- 曾尝试使用
createEntityAdapter实现状态更新,未达到预期效果
存在缺陷的原始代码
有问题的editCount异步thunk
export const editCount = createAsyncThunk('contas/editCount', async (data) => { const dados = data; axios.post('http://localhost:8080/api/teste/' + dados.documento, { Documento: dados.documento, Nome: dados.nome, Valor: dados.valor, Historico: dados.historico, DataEmissao: dados.dataEmissao, DataVencimento: dados.dataVencimento }).then(function (response) { console.log('teste', response.data) return response.data; }).catch(function (error) { console.log(error) }) })
原有slice的状态处理逻辑
const ContasReducer = createSlice({ name: sliceName, initialState: { contas: [], status: null }, reducers: {}, extraReducers: (builder) => { builder.addCase(fetchCounts.fulfilled , (state, { payload }) => { state.contas = payload state.status = 'success' }) builder.addCase(fetchCounts.pending , (state, action) => { state.status = 'Loading' state.contas = [{}] }) builder.addCase(createAcount.fulfilled , (state, action) => { state = action.payload console.log('action payload', action.payload) }) // 编辑账户的reducer处理逻辑存在错误 builder.addCase(editCount.fulfilled , (state, action) => { state.conta = action.meta.arg; console.log('reducer',action.meta.arg) }) } })
组件内的保存触发逻辑
function SalvarDados() { Dispatch( editCount({ documento: Documento, nome: Nome, valor: Valor, historico: Historico, dataEmissao: new Date(DataEmissao), dataVencimento: new Date(DataVencimento), }) ) props.CloseModal() }
问题根因
createAsyncThunk的回调函数要求必须显式返回最终需要传递给reducer的内容,原有代码的两个核心缺陷:
- 没有对
axios.post的调用结果做前置await处理,内部.then回调里的return仅在自身作用域生效,外层异步函数实际没有返回任何值,导致thunk触发fulfilled动作时payload为空,根本拿不到接口返回的最新数据。之前尝试用createEntityAdapter也无法生效,本质也是因为thunk没有拿到正确的接口返回值,adapter没有可处理的源数据。 - 原有editCount.fulfilled的状态更新逻辑,错误地把thunk接收的入参当成接口返回值,直接把入参赋值给
state.conta,没有用到服务端返回的最新数据做覆盖。
修正后的实现
修复后的editCount thunk逻辑
通过await等待axios请求完成,显式将接口响应作为thunk的返回值,确保thunk能拿到正确的服务端数据:
export const editCount = createAsyncThunk('contas/editCount', async (data) => { const dados = data; const response = await axios.post('http://localhost:8080/api/teste/' + dados.documento, { Documento: dados.documento, Nome: dados.nome, Valor: dados.valor, Historico: dados.historico, DataEmissao: dados.dataEmissao, DataVencimento: dados.dataVencimento }) return response.data; })
修正后的状态同步逻辑
在editCount.fulfilled的回调中,通过接口返回的最新数据匹配列表中的对应账户,完成状态覆盖:
注:原参考修正代码中
splice方法存在参数遗漏,完整的替换逻辑需要传入三个参数:目标索引、删除元素个数、用于替换的新元素,否则无法完成正确的列表更新。
builder.addCase(editCount.fulfilled , (state, {payload}) => { const [data] = payload; const contaIndex = state.contas.findIndex((obj) => obj.Documento === data.Documento) // 匹配到对应账户后替换为最新数据 const updatedContas = [...state.contas] updatedContas.splice(contaIndex, 1, data) state.contas = updatedContas })
内容的提问来源于stack exchange,提问作者Matheus Martins
相关产品推荐
相关产品推荐

