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
相关产品推荐
相关产品推荐

