Redux Dispatch异常:含Async函数时State为空数组问题排查
Redux Dispatch异步场景下状态为空的问题
执行dispatch操作后,Redux状态中本应存储对象数组,实际却得到空数组。移除代码中的异步函数部分后,dispatch可正常工作,但保留异步函数时状态始终为空。
相关代码
主逻辑代码
if(printDrawingsRedux.imagesCounter.length === 0) { // 创建用于统计图片占位块数量的数组 const arrNew = fd.map((value, index) => { let result return result = {...value, id: index, link: false, quantity: 1, type: value.type, name: value.name, blackWhitewRateCost: 50, colorRateCost: 100, drawingPages: [], currentNumberPage: 1, howManyPages: function () { return this.drawingPages.length }, modalPlusSize: false, } }) dispatch(setImageCounterDrawingsRedux(arrNew)) console.log(printDrawingsRedux.imagesCounter) }else{ const arrNew = fd.map((value, index) => { let result return result = {...value, id: index, link: false, quantity: 1, type: value.type, name: value.name, blackWhitewRateCost: 50, colorRateCost: 100, drawingPages: [], currentNumberPage: 1, howManyPages: function () { return this.drawingPages.length }, modalPlusSize: false, } }) let newState = [...printDrawingsRedux.imagesCounter, ...arrNew] let arrNew2 = newState.map((value, index) => { return {...value} = {...value, id: index} }) dispatch(setImageCounterDrawingsRedux(arrNew2)) } // 遍历创建好的数组填充内容 const promiseArrayBuffer = (file) => new Promise((resolve) => { var fileReader = new FileReader(); fileReader.onloadend = (e) => resolve(e.target.result); fileReader.readAsArrayBuffer(file); }); (async function () { for (let i = 0; i < fd.length; i++) { console.log("Hello2") if (fd[i].type === "image/jpeg" || fd[i].type === "image/jpg" || fd[i].type === "image/png" ){ console.log("Hello3") const arrayBuffer = await promiseArrayBuffer(fd[i]); var image = arrayBufferToBlob(arrayBuffer, fd[i].type) var url = URL.createObjectURL(image); let arrNew = printDrawingsRedux.imagesCounter.map((value, index) => { if (index === i) { return {...value} = {...value, link: url, drawingPages: {drawingSize: "А3 (297х420мм)", kindPrintDrawing: "чорно-білий друк", thicknessPaperDrawing: "80 г/щ", commentForPage: "", quantityDrawing: 1, personalSize1: 0, personalSize2: 0, quantity: 1, pageNotToPrint: false, personalSizeCounter: function () { return this.personalSize1 * this.personalSize2 / 1000000 }, } } }else{ return value } }) dispatch(setImageCounterDrawingsRedux(arrNew)) }else { console.log("pdf catched") } }})();
预期状态结构
{ id: index, link: false, quantity: 1, type: value.type, name: value.name, blackWhitewRateCost: 50, colorRateCost: 100, drawingPages: [], currentNumberPage: 1, howManyPages: function () { return this.drawingPages.length }, modalPlusSize: false }
Action代码
export const setImageCounterDrawingsRedux = (files) => { return { type: SET_IMAGECOUNTER_ASYNC_DRAWING, payload: files, } }
Reducer代码
case SET_IMAGECOUNTER_ASYNC_DRAWING: return {...state, printDrawings: {...state.printDrawings, imagesCounter: action.payload} }
问题原因及解决办法
1. 异步函数捕获旧状态快照
Redux通过useSelector返回的是状态快照,异步函数执行时会捕获初始的空数组状态,后续dispatch更新状态后,异步函数内的printDrawingsRedux不会自动更新,导致基于它生成的数组为空,覆盖之前的正确状态。
解决:
把初始生成的数组保存到本地变量,异步操作基于该变量修改,不依赖Redux状态:
// 先保存初始数组到本地变量 let initialImages = []; if(printDrawingsRedux.imagesCounter.length === 0) { initialImages = fd.map((value, index) => ({ ...value, id: index, link: false, quantity: 1, type: value.type, name: value.name, blackWhitewRateCost: 50, colorRateCost: 100, drawingPages: [], currentNumberPage: 1, howManyPages: function () { return this.drawingPages.length }, modalPlusSize: false })) dispatch(setImageCounterDrawingsRedux(initialImages)) }else{ const arrNew = fd.map((value, index) => ({ ...value, id: index, link: false, quantity: 1, type: value.type, name: value.name, blackWhitewRateCost: 50, colorRateCost: 100, drawingPages: [], currentNumberPage: 1, howManyPages: function () { return this.drawingPages.length }, modalPlusSize: false })) initialImages = [...printDrawingsRedux.imagesCounter, ...arrNew].map((val, idx) => ({...val, id: idx})) dispatch(setImageCounterDrawingsRedux(initialImages)) } // 异步操作基于本地变量处理 (async function () { let updatedImages = [...initialImages]; for (let i = 0; i < fd.length; i++) { if (fd[i].type.match(/image\/(jpeg|jpg|png)/)) { const arrayBuffer = await promiseArrayBuffer(fd[i]); const image = arrayBufferToBlob(arrayBuffer, fd[i].type) const url = URL.createObjectURL(image); updatedImages[i] = { ...updatedImages[i], link: url, drawingPages: { drawingSize: "А3 (297х420мм)", kindPrintDrawing: "чорно-білий друк", thicknessPaperDrawing: "80 г/щ", commentForPage: "", quantityDrawing: 1, personalSize1: 0, personalSize2: 0, quantity: 1, pageNotToPrint: false, personalSizeCounter: function () { return this.personalSize1 * this.personalSize2 / 1000000 } } } } } // 所有异步操作完成后一次性更新状态 dispatch(setImageCounterDrawingsRedux(updatedImages)) })();
2. 语法错误导致状态异常
arrNew2的map函数中,return {...value} = {...value, id: index}是无效语法,会返回undefined,导致dispatch后状态被设为undefined,后续异步读取到空数组。
解决:修正为正确的对象展开写法:
let arrNew2 = newState.map((value, index) => { return {...value, id: index} })
3. 循环中频繁dispatch导致状态覆盖
循环内每次dispatch都会覆盖整个数组,可能出现状态更新冲突。改为所有异步操作完成后一次性dispatch,减少状态更新次数,避免覆盖问题。
内容的提问来源于stack exchange,提问作者Tymokhovcev Valeriy
相关产品推荐
相关产品推荐

