React共用saveData方法新增产品/供应商时数据重复写入两次问题咨询
问题描述
我正在开发一个React应用,包含两个独立组件,分别实现产品(Products)和供应商(Suppliers)的增删改查功能。
两个组件的新增功能(用户填写完产品或供应商输入字段后点击保存触发)复用了同一个saveData方法,该方法存放在公共的ProductsAndSuppliers.js文件中,两个组件均可调用。
产品和供应商组件内都有表格展示预置的模拟数据,我在每个页面底部添加了新增按钮,根据用户左侧选中的标签(产品/供应商)新增对应类型数据。
由于两个场景复用同一个saveData方法,我在填写完输入字段尝试向对应表格新增产品或供应商时遇到了问题:新数据会被添加两次,暂时找不到问题原因。
我尝试过使用展开运算符向集合中添加新项,但没有解决问题,代码如下:
saveData = (collection, item) => { if (item.id === "") { item.id = this.idCounter++; this.setState((collection) => { return { ...collection, item } }) } else { this.setState(state => state[collection] = state[collection].map(stored => stored.id === item.id ? item : stored)) } }
最初版本的saveData方法如下,已经会触发新增重复两次的问题:
saveData = (collection, item) => { if (item.id === "") { item.id = this.idCounter++; this.setState(state => state[collection] = state[collection].concat(item)); } else { this.setState(state => state[collection] = state[collection].map(stored => stored.id === item.id ? item : stored)) } }
我的state结构如下:
this.state = { products: [ { id: 1, name: "Kayak", category: "Watersports", price: 275 }, { id: 2, name: "Lifejacket", category: "Watersports", price: 48.95 }, { id: 3, name: "Soccer Ball", category: "Soccer", price: 19.50 }, ], suppliers: [ { id: 1, name: "Surf Dudes", city: "San Jose", products: [1, 2] }, { id: 2, name: "Field Supplies", city: "New York", products: [3] }, ] }
问题根因
- 直接修改
setStateupdater函数传入的只读prevState对象,违反React state不可变原则,原state被提前修改后,setState触发二次更新时就会重复添加数据 setStateupdater函数返回值不符合要求:需要返回包含要更新的state字段的新对象,原写法要么直接给prevState赋值后返回数组,要么把updater的入参错当成collection名,完全没命中要更新的products/suppliers字段- 修改后的spread写法逻辑错误:updater的第一个参数永远是上一次的完整state对象,你将其命名为
collection并展开添加item,只会给根state新增一个叫item的属性,根本不会更新对应集合数组
修复后的代码
saveData = (collection, item) => { if (item.id === "") { item.id = this.idCounter++; this.setState(prevState => ({ [collection]: [...prevState[collection], item] })) } else { this.setState(prevState => ({ [collection]: prevState[collection].map(stored => stored.id === item.id ? item : stored ) })) } }
注意事项
- 永远不要直接修改prevState的属性,所有更新都要返回新的对象/数组
- 如果
saveData方法抽离在公共文件中,要确保调用时this正确绑定到对应组件实例,否则setState和idCounter都会读取失败
内容的提问来源于stack exchange,提问作者SuspensionBlues
相关产品推荐
相关产品推荐

