You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

提交表单至Firestore时遇addDoc()无效数据错误求助

Firestore存储表单数据时的错误排查

问题描述

提交表单将数据存储到Firestore数据库时触发错误,状态中images字段值异常,已尝试现有解决方案但未解决,相关代码如下:

const storeImage = async (image) => {
  return new Promise((resolve, reject) => {
    const storage = getStorage()
    const fileName = `${auth.currentUser.uid}-${image.name}-${uuidv4()}`

    const storageRef = ref(storage, 'images/' + fileName)

    const uploadTask = uploadBytesResumable(storageRef, image)

    uploadTask.on(
      'state_changed',
      (snapshot) => {
        const progress =
          (snapshot.bytesTransferred / snapshot.totalBytes) * 100
        console.log('Upload is ' + progress + '% done')
        switch (snapshot.state) {
          case 'paused':
            console.log('Upload is paused')
            break
          case 'running':
            console.log('Upload is running')
            break
          default:
            break
        }
      },
      (error) => {
        reject(error)
      },
      () => {
        // Handle successful uploads on complete
        getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
          resolve(downloadURL)
        })
      }
    )
  })
}

const imgUrls = await Promise.all(
  [...images].map((image) => storeImage(image))
).catch(() => {
  setLoading(false)
  toast.error('Images not uploaded')
  return
})

const formDataCopy = {
  ...formData,
  imgUrls,
  geolocation,
  timestamp: serverTimestamp(),
}

formDataCopy.location = address
delete formDataCopy.images
delete formDataCopy.address
!formDataCopy.offer && delete formDataCopy.discountedPrice

const docRef = await addDoc(collection(db, 'listings'), formDataCopy)
setLoading(false)
toast.success('Listing saved')
navigate(`/category/${formDataCopy.type}/${docRef.id}`)

问题分析与修复方案

1. Promise.all异常处理逻辑错误

原代码中Promise.all().catch()触发后返回undefined,导致imgUrls为undefined,后续仍执行Firestore写入操作,这会因字段类型不匹配触发错误。

修复:
改用try/catch结构,确保上传失败时直接终止后续流程:

try {
  const imgUrls = await Promise.all(
    [...images].map((image) => storeImage(image))
  )

  // 表单数据处理与Firestore写入逻辑移到try块内
  const formDataCopy = {
    ...formData,
    imgUrls,
    geolocation,
    timestamp: serverTimestamp(),
  }

  formDataCopy.location = address
  delete formDataCopy.images
  delete formDataCopy.address
  !formDataCopy.offer && delete formDataCopy.discountedPrice

  const docRef = await addDoc(collection(db, 'listings'), formDataCopy)
  setLoading(false)
  toast.success('Listing saved')
  navigate(`/category/${formDataCopy.type}/${docRef.id}`)
} catch (error) {
  setLoading(false)
  toast.error('Images not uploaded')
  return
}

2. 优化storeImage函数的异步逻辑

原函数中getDownloadURL使用then嵌套,可简化为await提升可读性,同时直接传递reject函数简化错误处理:

const storeImage = async (image) => {
  const storage = getStorage()
  const fileName = `${auth.currentUser.uid}-${image.name}-${uuidv4()}`
  const storageRef = ref(storage, 'images/' + fileName)
  const uploadTask = uploadBytesResumable(storageRef, image)

  return new Promise((resolve, reject) => {
    uploadTask.on(
      'state_changed',
      (snapshot) => {
        const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
        console.log(`Upload is ${progress}% done`)
        switch (snapshot.state) {
          case 'paused':
            console.log('Upload is paused')
            break
          case 'running':
            console.log('Upload is running')
            break
        }
      },
      reject,
      async () => {
        const downloadURL = await getDownloadURL(uploadTask.snapshot.ref)
        resolve(downloadURL)
      }
    )
  })
}

3. 校验images数据源有效性

确保images是可迭代的File对象集合(如input的files属性),并处理空图片的情况:

if (!images || images.length === 0) {
  toast.warning('请选择至少一张图片')
  setLoading(false)
  return
}

4. 检查Firestore规则与字段类型

确认Firestore的listings集合写入权限开放,且imgUrls字段被设置为数组类型(避免因类型不匹配触发错误)。

内容的提问来源于stack exchange,提问作者Abdessamad El-Maaroufi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:35:26