React+Firebase点击按钮动态修改ID及重复添加问题修复方案
问题分析与修复方案
核心问题原因
- 数据类型不匹配:
useLocalStorage初始值设为单个对象,但后续代码将list当作数组操作(如[...list, item]、list.filter),导致第一次操作后数据结构混乱,后续添加逻辑直接失效。 - 重复判断逻辑错误:用
list.indexOf(item)判断商品是否已存在,而对象的indexOf依赖引用相等——即使商品内容完全一致,只要引用不同就会判断为“未添加”,再加上初始数据类型错误,进一步加剧了问题。 - UUID生成时机不合理:仅在组件挂载时调用
getProducts生成UUID,后续无重新生成逻辑;且实际上无需手动生成UUID,直接使用原商品自带ID或Firebase文档ID更可靠。
具体修复步骤
1. 修正useLocalStorage初始值类型
将list的初始值从单个对象改为空数组,匹配后续数组操作的需求:
const [list, setList] = useLocalStorage('data', [])
2. 修复添加时的重复判断逻辑
替换indexOf为some方法,通过商品ID判断是否已存在,避免引用比较的问题:
const handleClick = async(item) => { // 通过ID判断是否已添加,而非对象引用 const isExist = list.some(product => product.id === item.id) if (isExist) return await addDoc(collection(db, 'list'), { id: item.id, image: item.image, name: item.name, priceTotal: item.priceTotal, category: item.category }) // 使用函数式更新获取最新状态,避免闭包导致的状态滞后 setList(prevList => [...prevList, item]) console.log(item) }
3. 优化ID生成逻辑(二选一即可)
你完全不需要手动生成UUID,以下两种方案更可靠:
- 方案一:使用原商品自带的ID
你的数据库中商品已经有自增ID(如1、2、3...),直接复用即可:const getProducts = async() => { const data = await ProductDataService.getAllProducts() setProducts(data.docs.map((doc) => doc.data())) } - 方案二:使用Firebase文档ID
如果原商品ID不可靠,直接用Firebase自动生成的文档ID:const getProducts = async() => { const data = await ProductDataService.getAllProducts() setProducts(data.docs.map((doc) => ({...doc.data(), id: doc.id}))) }
4. 确保删除逻辑的可靠性
在deleteProduct中同样使用函数式更新,保证获取最新的list状态:
const deleteProduct = (id) => { setList(prevList => prevList.filter((product) => product.id !== id)) // 可选:同步删除Firebase中的对应文档 // await deleteDoc(doc(db, 'list', id)) }
额外需求:点击时动态生成UUID
如果确实需要给添加到列表的商品生成新的UUID,可在点击时动态生成:
const handleClick = async(item) => { const isExist = list.some(product => product.id === item.id) if (isExist) return const newId = v4() // 点击时动态生成UUID await addDoc(collection(db, 'list'), { id: newId, image: item.image, name: item.name, priceTotal: item.priceTotal, category: item.category }) setList(prevList => [...prevList, {...item, id: newId}]) }
内容的提问来源于stack exchange,提问作者Eugene Kliuchnikov
相关产品推荐
相关产品推荐

