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

React+Firebase表单更新异常:未修改字段被设为空值

Firebase更新记录时未修改字段被设为空值

问题描述

用React表单更新Firebase中的分类记录,流程是先从URL获取记录ID,再更新对应文档。但出现以下问题:

  • 修改name字段提交后,name更新成功,但description被设为空值
  • 修改description字段提交后,description更新成功,但name被设为空值

原代码

export default CategoryUpdate
const CategoryUpdate = () => {

  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const params = useParams();  // get category id from url
  const [data, setData] = useState([]);

  useEffect(() => {
      const fetchData = async () => {
          const docRef = doc(db, "category", params.categoryId)
          const docSnap = await getDoc(docRef)
          if(docSnap.exists()){
              setData(docSnap.data())
          }
      };
      fetchData();
  },[params.categoryId]);

  // Updating category in Firebase
  const saveDetails = async () => {
    const updateSchool = {
        name: name,
        description: description,
    };
    try {
        const schoolRef = doc(db, "category", data.id)
        await updateDoc(schoolRef, updateSchool);
    } catch (error) {
        console.log(error);
    }
  }

  return ( 
    <form> 
      <input 
        type="text" 
        required 
        defaultValue={data.name || ''} 
        placeholder="Set a title" 
        onChange={(e) => setName(e.target.value)} 
      /> 

      <input 
        type="text" 
        required 
        defaultValue={data.description || ''} 
        placeholder="Set a title" 
        onChange={(e) => setDescription(e.target.value)} 
      /> 

      <div className='flex items-center w-full'> 
        <button type="button" 
          onClick={saveDetails}
        > 
          Edit Category 
        </button> 
      </div> 
  </form> 

  ) 
} 

export default CategoryUpdate

问题原因

  • name和description的初始状态是空字符串,且只有在输入框触发onChange时才会更新值
  • 当只修改一个字段时,另一个字段的状态仍然是空字符串,调用updateDoc时会把空值写入Firebase文档,覆盖原有数据

解决方案

方案1:初始化时同步表单状态

在获取Firebase数据后,把文档中的值同步到name和description状态中,这样未修改的字段会保留原始值:

useEffect(() => {
    const fetchData = async () => {
        const docRef = doc(db, "category", params.categoryId)
        const docSnap = await getDoc(docRef)
        if(docSnap.exists()){
            const fetchedData = docSnap.data()
            setData(fetchedData)
            // 同步初始化表单状态
            setName(fetchedData.name || '')
            setDescription(fetchedData.description || '')
        }
    };
    fetchData();
},[params.categoryId]);

方案2:用单个对象管理表单状态(更推荐)

把表单字段合并成一个状态对象,简化状态管理,同时避免单个字段状态不同步的问题:

const CategoryUpdate = () => {
  const [formData, setFormData] = useState({ name: '', description: '' });
  const params = useParams();

  useEffect(() => {
      const fetchData = async () => {
          const docRef = doc(db, "category", params.categoryId)
          const docSnap = await getDoc(docRef)
          if(docSnap.exists()){
              const fetchedData = docSnap.data()
              // 初始化表单数据
              setFormData({
                  name: fetchedData.name || '',
                  description: fetchedData.description || ''
              })
          }
      };
      fetchData();
  },[params.categoryId]);

  // 统一处理输入变化
  const handleInputChange = (e) => {
      const { name, value } = e.target;
      setFormData(prev => ({ ...prev, [name]: value }))
  }

  // Updating category in Firebase
  const saveDetails = async () => {
    try {
        // 直接用URL中的categoryId,避免依赖data.id可能不存在的问题
        const schoolRef = doc(db, "category", params.categoryId)
        await updateDoc(schoolRef, formData);
    } catch (error) {
        console.log(error);
    }
  }

  return ( 
    <form> 
      <input 
        type="text" 
        required 
        name="name"
        value={formData.name} 
        placeholder="Set a title" 
        onChange={handleInputChange} 
      /> 

      <input 
        type="text" 
        required 
        name="description"
        value={formData.description} 
        placeholder="Set a description" 
        onChange={handleInputChange} 
      /> 

      <div className='flex items-center w-full'> 
        <button type="button" onClick={saveDetails}> 
          Edit Category 
        </button> 
      </div> 
  </form> 
  ) 
} 

export default CategoryUpdate

额外注意事项

  • 原代码中data.id可能存在问题:Firebase文档的ID是docSnap.id,如果你的文档中没有手动存储id字段,data.id会是undefined,导致更新失败。推荐直接使用params.categoryId作为文档ID。

内容的提问来源于stack exchange,提问作者paniklas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:35:23