使用 ReactJS 更新 Firebase 中的文档

问题描述 投票:0回答:1

我正在开发一个用户个人资料页面,用户可以在其中更新他们的个人资料信息。用户第一次填写表单时,它会成功保存在 firestore 数据库中。但是下次当用户只想更新表单中的特定信息并单击“保存”时,整个文档都会更新。只有更改的字段信息会反映在数据库中,其余所有字段都变为空。

我尝试使用Firebase提供的updateDoc()函数,但我无法使用用户uid更新信息,以便数据库知道哪个用户更改了他们的信息。

个人资料页面.jsx

const { user } = UserAuth();

const [firstName, setFirstName] = useState("")
const [lastName, setLastName] = useState("")
const [email, setEmail] = useState("")
const [file, setFile] = useState("")
const [channelName, setChannelName] = useState("")
const [channelLink, setChannelLink] = useState("")

const [data, setData] = useState([])

const profileDB = collection(db, "UserProfiles");

const handleUpload = (e) => {
    e.preventDefault();
    console.log(e.target.files[0]);
    const Imgs = ref(storage, `profilePictures/${uuid()}`);
    uploadBytes(Imgs, e.target.files[0]).then((data) => {
        console.log(data, "imgs");
        getDownloadURL(data.ref).then((val) => {
            setFile(val);
        });
    });
    setFile("")
};

const handleClick = async (e) => {
    e.preventDefault();
    
    await setDoc(doc(profileDB, user.uid), {
        uid: user.uid,
        firstName: firstName,
        lastName: lastName,
        email: email,
        channelName: channelName,
        channelLink: channelLink,
        ImgURL: file
    });
    alert("Data added successfully");
    setFile("")
};

const handleUpdate = async () => {
    const updateData = doc(db, "userProfile", user.uid);
    await updateDoc(updateData, {
        firstName: firstName,
        lastName: lastName,
        email: email,
        channelLink: channelLink,
        channelName: channelName,
        ImgURL: file,
    })
}

// get user data according to user uid 
const getData = async () => {
    const profileDB = doc(db, "UserProfiles", user.uid);
    const profileDBSnap = await getDoc(profileDB);
    setData(profileDBSnap.data())
    console.log([data])
};

useEffect(() => {
    getData()
},[])

return (
 {
     [data].map((item) => (
                <>
                    <div className='max-w-[1280px] mx-auto flex items-center justify-between relative bottom-10'>

                        <div className='flex items-center gap-6'>
                            <div>
                                <img className='h-40 w-40 rounded-full' src={ item?.ImgURL || user?.photoURL || ProfilePic} alt="profile photo" />
                            </div>
                            <div>
                                <h1 className='text-3xl font-medium'>{ item?.firstName || user?.displayName || "User"}</h1>
                                <p className='text-[#667085]'>@{ item?.firstName || user?.displayName || "user"}</p>
                            </div>
                        </div>

                        <div className='flex items-center gap-3'>
                            <Link to={"/influencer/infdashboard"}>
                                <Button style={"border border-[#D0D5DD] bg-white py-2 px-4 rounded-lg text-sm font-semibold py-[10px]"} text={"Cancel"} />
                            </Link>

                            <Button style={"bg-[#F26522] text-white text-sm font-semibold rounded-lg px-4 py-[10px]"} text={"Save"} />
                        </div>
                    </div>

                    <form className='max-w-[640px] mx-auto'>
                        <div className='flex flex-col md:flex md:flex-row md:items-center md:justify-between gap-6 border-b border-[#EAECF0] pb-5'>
                            <div className='flex flex-col gap-[6px] w-full'>
                                <label className='text-[#344054] text-sm font-medium'>
                                    First name
                                </label>
                                <input type="text" placeholder={ item?.firstName || 'first name'} value={firstName} onChange={(e) => setFirstName(e.target.value)} className='outline-1 border border-gray-300 outline-[#F26522] p-2 rounded-lg' />
                            </div>

                            <div className='flex flex-col gap-[6px] w-full'>
                                <label className='text-[#344054] text-sm font-medium'>
                                    Last name
                                </label>
                                <input type="text" placeholder={ item?.lastName || 'last name'} value={lastName} onChange={(e) => setLastName(e.target.value)} className='outline-1 border border-gray-300 outline-[#F26522] p-2 rounded-lg' />
                            </div>
                        </div>

                        <div className='py-5 flex flex-col gap-[6px] border-b border-[#EAECF0]'>
                            <label className='text-[#344054] text-sm font-medium'>
                                Email
                            </label>
                            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder={ item?.email || '[email protected]'} className='outline-1 border border-gray-300 outline-[#F26522] p-2 rounded-lg' />
                        </div>

                        <div className='py-5 flex items-start gap-5 border-b border-[#EAECF0]'>
                            <img className='h-16 w-16 rounded-full' src={ item?.ImgURL || user?.photoURL || Avatar} alt="pic" />

                            <div className='bg-white w-full rounded-lg border border-[#EAECF0] flex flex-col justify-center items-center px-6 py-4'>
                                <input type="file" onChange={(e) => handleUpload(e)} />
                                <img src={UploadPic} alt="upload profile pic" />
                                <p className='text-[#667085] text-xs pt-3 text-center'><span className='text-[#4285F4] text-sm font-semibold tracking-wide'>Click to upload profile photo</span> or drag and drop <br /> SVG, PNG, JPG or GIF (max. 800x400px) </p>
                            </div>
                        </div>

                        <div className='py-5 border-b border-[#EAECF0]'>
                            <div className='flex flex-col gap-[6px] w-full pb-5'>
                                <label className='text-[#344054] text-sm font-medium'>
                                    Channel Name
                                </label>
                                <input type="text" placeholder={ item?.channelName || "Channel Name"} value={channelName} onChange={(e) => setChannelName(e.target.value)} className='outline-1 border border-gray-300 outline-[#F26522] p-2 rounded-lg' />
                            </div>

                            <div className='flex flex-col gap-[6px] w-full'>
                                <label className='text-[#344054] text-sm font-medium'>
                                    Channel Link
                                </label>
                                <input type="text" placeholder={ item?.channelLink || "Channel Link"} value={channelLink} onChange={(e) => setChannelLink(e.target.value)} className='outline-1 border border-gray-300 outline-[#F26522] p-2 rounded-lg' />
                            </div>
                        </div>

                        <div className='flex justify-end gap-3 py-5 '>
                            <Link to={"/influencer/infdashboard"}>
                                <Button style={"border border-[#D0D5DD] bg-white py-2 px-4 rounded-lg text-sm font-semibold py-[10px] md:w-max"} text={"Cancel"} />
                            </Link>

                            <Button style={"bg-[#F26522] text-white text-sm font-semibold rounded-lg px-4 py-[10px] md:w-max"} text={"Save"} event={handleClick} />

                        </div>

                    </form>
                </>
            ))
        }
reactjs firebase google-cloud-firestore react-hooks
1个回答
0
投票

听起来这段代码没有做你想做的事:

await updateDoc(updateData, {
    firstName: firstName,
    lastName: lastName,
    email: email,
    channelLink: channelLink,
    channelName: channelName,
    ImgURL: file,
})

当您调用

updateDoc
时,Firestore 会将您在数据库中指定的任何字段的值替换为您在调用中指定的值。因此,如果某些值为空,这些字段在数据库中将变为空。

要保持字段不被修改,您应该在调用中指定这些字段。例如,这只会修改

firstName
lastName
并保留其他字段不变:

await updateDoc(updateData, {
    firstName: firstName,
    lastName: lastName,
})

如果您事先不知道哪些字段有值,您可以使用以下方法动态构建对象:

let updates = {};
if (firstName && firstName.length > 0) updates['firstName'] = firstName;
if (lastName && lastName.length > 0) updates['lastName'] = lastName;
if (email && email.length > 0) updates['email'] = email;
if (channelLink && channelLink.length > 0) updates['channelLink'] = channelLink;
if (channelName && channelName.length > 0) updates['channelName'] = channelName;

await updateDoc(updateData, updates)

我在上面的示例中遗漏了

ImgURL
/
file
,因为我不知道它的类型,但您必须对此进行类似的检查。

© www.soinside.com 2019 - 2024. All rights reserved.