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

Next.js应用上传文本/图片触发运行时错误求助

问题:发布带图片的帖子时数据库存入成功但触发运行时错误

我参照在线教程开发了支持用户发布内容并可选上传图片的功能,前端采用Next.js,数据库使用Firestore。点击提交按钮时,帖子可成功存入数据库,但会触发运行时错误,界面及控制台均报错。在uploadString前执行console.log(selectedFile),结果显示selectedFile为null。

相关代码如下:

/* eslint-disable @next/next/no-img-element */
import { EmojiHappyIcon, PhotographIcon } from '@heroicons/react/outline';
import {
  addDoc,
  collection,
  serverTimestamp,
  updateDoc,
} from 'firebase/firestore';
import { getDownloadURL, ref, uploadString } from 'firebase/storage';
import { useSession, signOut } from 'next-auth/react';
import { useRef, useState } from 'react';
import { db, storage } from '../firebase';

export default function Input() {
  const { data: session } = useSession();
  const [input, setInput] = useState('');
  const [selectedFile, setSelectedFile] = useState(null);
  const filePickerRef = useRef(null);

  const sendPost = async () => {
    const docRef = await addDoc(collection(db, 'posts'), {
      id: session.user.uid,
      text: input,
      userImg: session.user.image,
      timestamp: serverTimestamp(),
      name: session.user.name,
      username: session.user.username,
    });

    const imageRef = ref(storage, `posts/${docRef.id}/image`);

    if (setSelectedFile) {
      await uploadString(imageRef, selectedFile, 'data_url').then(async () => {
        const downloadURL = await getDownloadURL(imageRef);
        await updateDoc(doc(db, 'posts', docRef.id), {
          image: downloadURL,
        });
      });
    }

    setInput('');
  };

  const addImageToPost = (e) => {
    const reader = new FileReader();
    if (e.target.files[0]) {
      reader.readAsDataURL(e.target.files[0]);
    }

    reader.onload = (readerEvent) => {
      setSelectedFile(readerEvent.target.result);
    };
  };

  return (
    <>
      {session && (
        <div className="flex border-b border-gray-200 p-3 space-x-3">
          <img
            onClick={signOut}
            src={session?.user?.image}
            alt="user-img"
            className="h-11 w-11 rounded-full cursor-pointer hover:brightness-95"
          />
          <div className="w-full divide-y divide-gray-200">
            <div className="">
              <textarea
                className="w-full border-none focus:ring-0 text-lg placeholder-gray-700 tracking-wide min-h-[50px] text-gray-700 font-['Quattrocento']"
                rows="2"
                placeholder="Share a news article you want others to comment on!"
                value={input}
                onChange={(e) => setInput(e.target.value)}
              ></textarea>
            </div>
            <div className="flex items-center justify-between pt-2.5">
              <div className="flex">
                <div onClick={() => filePickerRef.current.click()}>
                  <PhotographIcon className="h-10 w-10 hoverEffect p-2 text-gray-500 hover:bg-gray-100 " />
                  <input
                    type="file"
                    hidden
                    ref={filePickerRef}
                    onClick={addImageToPost}
                  />
                </div>
                <EmojiHappyIcon className="h-10 w-10 hoverEffect p-2 text-gray-500 hover:bg-gray-100" />
              </div>
              <button
                onClick={sendPost}
                disabled={!input.trim()}
                className="bg-gray-500 text-white px-4 py-1.5 rounded font-bold shadow-md hover:brightness-95 disabled:opacity-50 font-['Quattrocento']"
              >
                Comment
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}

错误排查及解决建议

错误根源

代码中的if (setSelectedFile)判断逻辑完全错误:setSelectedFile是React的state更新函数,永远为真值,这导致即使用户没有选择图片(selectedFile为null),也会执行uploadString操作,而Firebase的uploadString无法接受null作为数据源,从而触发运行时错误。

修复步骤

  1. 修正上传判断条件
    将if (setSelectedFile)改为if (selectedFile),仅当用户确实选择了图片时才执行上传逻辑:

    if (selectedFile) {
      await uploadString(imageRef, selectedFile, 'data_url').then(async () => {
        const downloadURL = await getDownloadURL(imageRef);
        await updateDoc(doc(db, 'posts', docRef.id), {
          image: downloadURL,
        });
      });
    }
    
  2. 重置图片选择状态
    上传完成后重置selectedFile为null,避免下次发布时重复上传之前的图片:

    if (selectedFile) {
      // 上传逻辑...
      setSelectedFile(null);
    }
    
  3. 修复文件选择事件绑定
    文件选择器的onClick事件改为onChange,避免用户打开文件选择框但取消选择时,addImageToPost被错误触发:

    <input
      type="file"
      hidden
      ref={filePickerRef}
      onChange={addImageToPost}
    />
    

内容的提问来源于stack exchange,提问作者user18792970

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:35:22