如何在Cloud Firestore中将日期转换为Timestamp存储
解决React中Cloud Firestore存储生日为Timestamp类型的问题
问题描述
在React项目中使用Cloud Firestore时,希望将用户通过type="date"输入框提交的生日日期以Timestamp类型存储到数据库,但目前传入的是字符串格式,无法直接存储为Timestamp。
问题根源
你的代码中,birthDate初始值是Timestamp,但在日期输入框的onChange事件中,直接将event.target.value(字符串格式的日期,如"2024-05-20")赋值给了birthDate,导致最终存入Firestore的是字符串而非Timestamp类型。
解决方案
只需在将日期存入Firestore时,把字符串格式的日期转换为Firestore的Timestamp即可,有两种实现方式:
方式1:提交数据时转换(推荐)
保持state中存储用户输入的字符串日期,在调用addDoc时转换为Timestamp,这样既方便后续展示原始输入,又能正确存储类型:
- 调整
birthDate的初始状态:
const [birthDate, setBirthDate] = useState(""); // 初始为空字符串,符合用户未输入的状态
- 修改日期输入框的
onChange(无需额外转换,直接存字符串):
<input type="date" name="data_nascimento" id="data_nascimento" required onChange={(event) => { setBirthDate(event.target.value); }} />
- 在
handleRegister的addDoc中转换为Timestamp:
await addDoc(userCollectionRef, { tipoUsuario: 'aluno', idUsuario: auth.currentUser.uid, nome, email, curso, dataNascimento: Timestamp.fromDate(new Date(birthDate)), // 核心转换代码 });
方式2:输入时直接转换为Timestamp
在用户选择日期时,直接将字符串转换为Timestamp并存入state:
<input type="date" name="data_nascimento" id="data_nascimento" required onChange={(event) => { const selectedDate = new Date(event.target.value); setBirthDate(Timestamp.fromDate(selectedDate)); }} />
这种方式下,state中直接存储Timestamp,后续提交时可直接传入addDoc。
额外优化:修复用户创建与数据存储的顺序问题
你的原代码中,createUserWithEmailAndPassword同时使用了await和.then(),可能导致在用户数据存入Firestore前就跳转到首页,引发数据存储失败。建议调整为顺序执行:
const handleRegister = async () => { try { // 先等待用户账号创建完成 const userCredential = await createUserWithEmailAndPassword( auth, registerEmail, registerPassword ); // 设置登录状态 localStorage.setItem("isAuth", true); setIsAuth(true); // 存入用户详细信息到Firestore await addDoc(userCollectionRef, { tipoUsuario: 'aluno', idUsuario: userCredential.user.uid, // 直接从userCredential获取uid更可靠 nome, email, curso, dataNascimento: Timestamp.fromDate(new Date(birthDate)), }); // 最后跳转首页 navigate("/home"); console.log(userCredential.user); } catch (error) { console.log(error.message); } };
完整修改后的代码
import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import { createUserWithEmailAndPassword } from "firebase/auth"; import { collection, addDoc, Timestamp, } from "firebase/firestore"; import { auth, db } from "../firebase-config"; function Register({ setIsAuth }) { let navigate = useNavigate(); const VoltarLogin = () => { navigate("/login"); }; const [registerEmail, setRegisterEmail] = useState(""); const [registerPassword, setRegisterPassword] = useState(""); const [nome, setNome] = useState(""); const [email, setEmail] = useState(""); const [curso, setCurso] = useState(""); const [birthDate, setBirthDate] = useState(""); // 修改初始值 const userCollectionRef = collection(db, "usuarios"); const handleRegister = async () => { try { const userCredential = await createUserWithEmailAndPassword( auth, registerEmail, registerPassword ); localStorage.setItem("isAuth", true); setIsAuth(true); await addDoc(userCollectionRef, { tipoUsuario: 'aluno', idUsuario: userCredential.user.uid, nome, email, curso, dataNascimento: Timestamp.fromDate(new Date(birthDate)), }); navigate("/home"); console.log(userCredential.user); } catch (error) { console.log(error.message); } }; return ( <div className="box"> <div className="center-box-register"> <div className="card-register"> <h1>Cadastro</h1> <div className="linha"> </div> <div className="textfield"> <label htmlFor="name">Nome:</label> <input type="text" name="nome" id="nome" placeholder="Digite seu nome" required onChange={(event) => { setNome(event.target.value); }}> </input> </div> <div className="textfield"> <label htmlFor="email">E-mail:</label> <input type="email" className="email" id="email" placeholder="Digite seu e-mail" required onChange={(event) => { setRegisterEmail(event.target.value); setEmail(event.target.value); }}> </input> </div> <div className="textfield"> <label htmlFor="senha">Senha:</label> <input type="password" name="senha" id="senha" placeholder="Digite sua senha" required onChange={(event) => { setRegisterPassword(event.target.value); }}> </input> </div> <div className="cursos"> <label htmlFor="user">Selecione seu curso: </label> <select name="user" id="user" required onChange={(event) => { setCurso(event.target.value); }}> <option disabled selected> Curso... </option> <option value="mtecaai">M-TEC PI | Administração</option> <option value="mtecds">M-TEC PI | Desenvolvimento de Sistemas</option> <option value="mtecaqi">M-TEC PI | Química</option> <option value="etimaai">ETIM Administração</option> <option value="etimds">ETIM Desenvolvimento de Sistemas</option> <option value="erimaqi">ETIM Química</option> <option value="eadaai">Administração - EAD</option> <option value="rh">Recursos Humanos</option> <option value="sec">Secretariado</option> <option value="log">Logística</option> </select> </div> <div className="textfield"> <label htmlFor="data_nascimento">Data de nascimento:</label> <input type="date" name="data_nascimento" id="data_nascimento" required onChange={(event) => { setBirthDate(event.target.value); }}> </input> </div> <button name="submit" id="submit" className="btn-cadastro" onClick={handleRegister}>Cadastrar-se</button> <div className="lin2"> </div> <div className="login"> <button onClick={VoltarLogin} className="btn-voltar">Já tem uma conta?</button> </div> </div> </div> </div> ) } export default Register;
内容的提问来源于stack exchange,提问作者Carlos03
相关产品推荐
相关产品推荐

