React项目Firebase图片上传报错:childPath.split is not function求助
问题:React + Firebase 图片上传报错 TypeError: childPath.split is not a function
错误信息
TypeError: childPath.split is not a function at child (http://localhost:3000/static/js/bundle.js:24099:40) at _getChild$1 (http://localhost:3000/static/js/bundle.js:25823:19) at refFromPath (http://localhost:3000/static/js/bundle.js:25872:14) at refFromPath (http://localhost:3000/static/js/bundle.js:25865:14) at ref$1 (http://localhost:3000/static/js/bundle.js:25886:12) at ref (http://localhost:3000/static/js/bundle.js:26249:10) at uploadFiles (http://localhost:3000/main.a1c7807c27fe7005bb39.hot-update.js:52:79) at http://localhost:3000/main.a1c7807c27fe7005bb39.hot-update.js:75:13 at commitHookEffectListMount (http://localhost:3000/static/js/bundle.js:55328:30) at commitPassiveMountOnFiber (http://localhost:3000/static/js/bundle.js:56821:17)
相关代码
import React, { useEffect, useState } from "react"; import { db, storage } from "../../Firebase-Config"; import { collection, getDocs, addDoc } from "firebase/firestore"; import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; import "../../../src/App.css"; const ShowPost = () => { const [user, setUser] = useState([]); const [data, setData] = useState({}); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [estate, setEstate] = useState(""); const [file, setFile] = useState([]); const userCollectionRef = collection(db, "posts"); const handleButton = async () => { await addDoc(userCollectionRef, { name: name, description: description, estate: estate, }); }; useEffect(() => { const uploadFiles = () => { const fileName = new Date().getTime() + file.name; console.log(fileName); const storageRef = ref(storage, fileName); const uploadTask = uploadBytesResumable(storageRef, fileName); uploadTask.on( "state_changed", (snapshot) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log("Upload is " + progress + "% done"); switch (snapshot.state) { case "paused": console.log("Upload is paused"); break; case "running": console.log("Upload is running"); break; default: break; } }, (error) => { console.log(error); }, () => { getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { console.log("File available at", downloadURL); }); } ); }; file && uploadFiles(); }, [file]); useEffect(() => { const getUsers = async () => { const data = await getDocs(userCollectionRef); setUser(data.docs.map((doc) => ({ ...doc.data(), id: doc.id }))); // console.log(data); }; getUsers(); }, []); return ( <div> <input type="file" onChange={(e) => { setFile(e.target.files[0]); }} /> <input type="text" onChange={(e) => { setName(e.target.value); }} placeholder="estate" /> <input type="text" onChange={(e) => { setDescription(e.target.value); }} placeholder="description" /> <input type="text" onChange={(e) => { setEstate(e.target.value); }} placeholder="name" /> <button onClick={handleButton}>Click me</button> <div className="square center-div"> {user.map((item) => { return ( <div> <div className="circle-pfp">{item.description}</div> <h3>{item.estate}</h3> <h1>{item.name}</h1> </div> ); })} </div> </div> ); }; export default ShowPost;
解决方案
1. 修复上传参数错误
uploadBytesResumable 第二个参数需要传入文件对象,而非文件名。原代码中传了fileName字符串,导致Firebase无法处理,改为传入file对象:
const uploadTask = uploadBytesResumable(storageRef, file);
2. 修正文件状态初始化
文件状态应该是单个对象,不是数组,初始化改为:
const [file, setFile] = useState(null);
3. 添加图片URL状态并关联Firestore
新增状态存储图片URL,上传完成后更新,并在提交时存入Firestore:
// 新增状态 const [imageUrl, setImageUrl] = useState(""); // 在上传完成的回调中更新状态 () => { getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { console.log("File available at", downloadURL); setImageUrl(downloadURL); // 保存URL到状态 }); } // 修改handleButton,存入图片URL const handleButton = async () => { await addDoc(userCollectionRef, { name: name, description: description, estate: estate, imageUrl: imageUrl // 添加图片URL字段 }); };
4. 优化上传触发条件
确保file存在且为有效文件对象时才执行上传,避免初始空值触发错误:
file instanceof File && uploadFiles();
修改后的完整代码
import React, { useEffect, useState } from "react"; import { db, storage } from "../../Firebase-Config"; import { collection, getDocs, addDoc } from "firebase/firestore"; import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; import "../../../src/App.css"; const ShowPost = () => { const [user, setUser] = useState([]); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [estate, setEstate] = useState(""); const [file, setFile] = useState(null); const [imageUrl, setImageUrl] = useState(""); const userCollectionRef = collection(db, "posts"); const handleButton = async () => { if (!imageUrl) { console.warn("请等待图片上传完成后再提交"); return; } await addDoc(userCollectionRef, { name: name, description: description, estate: estate, imageUrl: imageUrl }); // 提交后清空表单 setName(""); setDescription(""); setEstate(""); setFile(null); setImageUrl(""); }; useEffect(() => { const uploadFiles = () => { const fileName = `${new Date().getTime()}-${file.name}`; const storageRef = ref(storage, fileName); const uploadTask = uploadBytesResumable(storageRef, file); uploadTask.on( "state_changed", (snapshot) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log(`Upload is ${progress}% done`); }, (error) => { console.error("上传失败:", error); }, () => { getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { console.log("文件地址:", downloadURL); setImageUrl(downloadURL); }); } ); }; file instanceof File && uploadFiles(); }, [file]); useEffect(() => { const getUsers = async () => { const data = await getDocs(userCollectionRef); setUser(data.docs.map((doc) => ({ ...doc.data(), id: doc.id }))); }; getUsers(); }, []); return ( <div> <input type="file" onChange={(e) => setFile(e.target.files[0])} value={file ? file.name : ""} /> <input type="text" onChange={(e) => setName(e.target.value)} placeholder="estate" value={name} /> <input type="text" onChange={(e) => setDescription(e.target.value)} placeholder="description" value={description} /> <input type="text" onChange={(e) => setEstate(e.target.value)} placeholder="name" value={estate} /> <button onClick={handleButton} disabled={!imageUrl}>提交</button> <div className="square center-div"> {user.map((item) => { return ( <div key={item.id}> {item.imageUrl && <img src={item.imageUrl} alt={item.name} className="circle-pfp" />} <div className="circle-pfp">{item.description}</div> <h3>{item.estate}</h3> <h1>{item.name}</h1> </div> ); })} </div> </div> ); }; export default ShowPost;
内容的提问来源于stack exchange,提问作者MOHIT RANA
相关产品推荐
相关产品推荐

