Firestore存储select表单值为字符串 如何改为数字类型存储
问题背景
向Firestore写入集合数据时,所有字段值默认被存储为字符串类型,需要将spicylevel(辣度)、servings(份量)字段以数字类型存入。
此前针对input输入框使用e.target.valueAsNumber可正常获取数字类型值存入,但该方法对select下拉选择框不生效,提交表单时会触发“请填写所有字段”的校验报错,相关实现代码如下:
const [menu, setMenu] = useState([]) const [form, setForm] = useState({ kookid: "", kookname: "", name: "", cuisine: "", foodtype: "", spicylevel: "", servings: "", price: "", description: "", }) const menuCollectionRef = collection(db, "menu") useEffect(() => { onSnapshot(menuCollectionRef, snapshot => { setMenu(snapshot.docs.map(doc => { return { id: doc.id, viewing: false, ...doc.data() } })) }) }, []) const handleSubmit = e => { e.preventDefault() if ( !form.kookid || !form.kookname || !form.name || !form.cuisine || !form.foodtype || !form.spicylevel || !form.servings || !form.price || !form.description ) { alert("Please fill out all fields") return } addDoc(menuCollectionRef, form) setForm({ kookid: "", kookname: "", name: "", cuisine: "", foodtype: "", spicylevel: "", servings: "", price: "", description: "", }).then(() => { }) } <div className="form-group2"> <label>Spicy Level</label> <select onChange={e => setForm({ ...form, spicylevel: e.target.value })}> <option value="">Select Spicy Level</option> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> </div>
问题原因
- select元素原生返回值为字符串类型,不存在
valueAsNumber属性,直接取值永远是字符串,无法像input一样直接拿到数字类型 - 原有校验逻辑使用
!字段值判断是否为空,当辣度选择合法值0时,数字0属于falsy值,会被误判为未填写,触发校验报错
修复方案
- select取值时手动做类型转换:空选项保留空字符串,选中有效选项时将字符串值转为数字再存入state,避免空值被提前转成0
- 调整数字字段的校验逻辑,将“判断值是否为falsy”改为“判断值是否为空字符串”,区分合法数字0和未填写的空状态
关键修改代码
select组件修改
<div className="form-group2"> <label>Spicy Level</label> <select onChange={e => { const selectVal = e.target.value; setForm({ ...form, spicylevel: selectVal === "" ? "" : Number(selectVal) }) }}> <option value="">Select Spicy Level</option> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> </div>
servings字段如果使用select选择,复用上述类型转换逻辑即可;如果是input输入框,继续使用e.target.valueAsNumber取值即可。
提交校验逻辑修改
const handleSubmit = e => { e.preventDefault() if ( !form.kookid || !form.kookname || !form.name || !form.cuisine || !form.foodtype || // 数字类型字段单独判断空字符串,避免把0误判为空 form.spicylevel === "" || form.servings === "" || !form.price || !form.description ) { alert("Please fill out all fields") return } addDoc(menuCollectionRef, form) setForm({ kookid: "", kookname: "", name: "", cuisine: "", foodtype: "", spicylevel: "", servings: "", price: "", description: "", }) }
如果price字段也需要存储为数字类型,按照相同逻辑做取值转换和校验调整即可,修改后提交到Firestore的对应字段会自动以数字类型存储。
内容的提问来源于stack exchange,提问作者siddhant kumar
相关产品推荐
相关产品推荐

