React+Redux Toolkit提交新增交易后列表组件不自动更新
问题根因
- 异步请求时序错误:你在新增交易的提交逻辑中同步dispatch了
addTransaction和getTransactions两个异步thunk,getTransactions发起GET请求时,POST请求大概率还未完成、数据尚未写入数据库,因此拿到的是新增前的旧数据。 - Redux状态更新逻辑缺失:
transactionsSlice中addTransaction.fulfilled回调仅修改了loading状态,没有将新增的交易数据写入transactions数组,即使POST请求成功,本地存储的交易列表也不会变化。 - 后端接口返回值不符合预期:POST接口插入数据后仅返回了数据库执行的结果对象(包含
affectedRows、insertId等元信息),没有返回完整的新增交易记录,无法直接用于前端状态更新。 - 附带逻辑bug:所有rejected回调中
state.error = state.error.message写法错误,初始状态下state.error为null,执行这行代码会直接报错,错误信息实际存储在action.error中。另外原后端SQL直接拼接用户输入存在严重SQL注入风险。
修复方案
方案一:本地直接更新状态(推荐,减少冗余请求)
- 修改后端POST接口,插入成功后返回完整的新增交易记录,同时改用参数化查询避免SQL注入:
app.post('/transactions',(req, res) => { const {transactionName, amount} = req.body; const insertQuery = `INSERT INTO transactions (title, amount) VALUES (?, ?)` db.query(insertQuery, [transactionName, amount], (err, result) => { if(err){ return res.status(500).send(err) } const selectQuery = `SELECT * FROM transactions WHERE id = ?` db.query(selectQuery, [result.insertId], (err, newTransaction) => { if(err) return res.status(500).send(err) res.send(newTransaction[0]) }) }) });
- 修改Slice中
addTransaction.fulfilled回调,将新交易追加到列表中,同时修复错误处理逻辑:
[addTransaction.fulfilled]: (state, {payload}) => { state.loading = false; // 按你的展示顺序选择unshift(头部新增)或push(尾部新增) state.transactions.unshift(payload); state.error = null; }, [addTransaction.rejected]: (state, action) => { state.loading = false; state.error = action.error?.message || '新增交易失败'; }, // 同步修复getTransactions的rejected回调 [getTransactions.rejected]: (state, action) => { state.loading = false; state.error = action.error?.message || '获取交易列表失败'; }
- 修改新增组件的提交逻辑,等待新增请求完成后再清空表单,不需要额外调用拉取列表的接口:
const handleSubmit = async (e) => { e.preventDefault(); const data = { transactionName, amount } if(transactionName && amount){ try { await dispatch(addTransaction(data)).unwrap(); setTransactionName('') setAmount(''); } catch(err) { // 可在此处新增失败提示逻辑 console.error('新增失败', err) } } }
方案二:新增成功后重新拉取全量列表
如果不想在本地维护状态更新,可以等新增请求完全落库后再触发列表拉取,不需要修改Slice的addTransaction.fulfilled逻辑,仅需要修改提交函数:
const handleSubmit = async (e) => { e.preventDefault(); const data = { transactionName, amount } if(transactionName && amount){ try { await dispatch(addTransaction(data)).unwrap(); // 等待POST请求完成、数据写入数据库后再拉取最新列表 dispatch(getTransactions()); setTransactionName('') setAmount(''); } catch(err) { console.error('操作失败', err) } } }
注意:该方案每次新增交易都会多发一次全量列表请求,数据量大时性能弱于方案一。
内容的提问来源于stack exchange,提问作者Amauri Santos
相关产品推荐
相关产品推荐

