You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:02:32