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

React图片上传组件出现Uncaught NotFoundError报错求助

问题:React图片上传组件选择图片后页面空白,报removeChild错误

我正在开发一个带自定义模态框的React图片上传组件,选择图片后本该预览图片,但页面直接变空白。模态框是在当前页面上方弹出的。

组件代码(TypeScript)

import React, { useState, useRef } from "react";

const ImgUpldChild = () => {
  const [image, setImage] = useState<string | null>("https://upload.wikimedia.org/wikipedia/commons/thumb/4/48/Outdoors-man-portrait_%28cropped%29.jpg/640px-Outdoors-man-portrait_%28cropped%29.jpg");
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  const removeImage = () => {
    setImage(null);
  };

  const fileInputRef = useRef<HTMLInputElement>(null);

  // Open file picker when div is clicked
  const handleDivClick = () => {
    if (fileInputRef.current) {
      fileInputRef.current.click();
    }
  };

  // Handle image selection
  const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];

    if (!file) {
        console.warn("No file selected");
        return;
    }

    const reader = new FileReader();

    reader.onload = () => {
        try {
            console.log("FileReader triggered");
            console.log("FileReader result type:", typeof reader.result);
            console.log("FileReader result:", reader.result);

            if (typeof reader.result === "string") {
                setTimeout(() => setImage(reader.result as string), 1000);
            }
        } catch (error) {
            console.error("Error in reader.onload:", error);
        }
    };

    reader.readAsDataURL(file);
};


  return (
    <div>
      <div className="row">
        <div className="col-sm-4 mb-4">
          <div className="form-group">
            <label className="guardian-img-box col-11">
              Father’s Photo

              {image ? (
                <div className="img-dlt-div">
                  <img src={image} alt="" className="preview-image" />
                  <button onClick={removeImage} className="delete-button">
                    <i className="far fa-trash-alt"></i>
                  </button>
                </div>
              ) : (
                <div className="upload-icon" onClick={openModal}>
                  <i className="fa-solid fa-arrow-up-from-bracket"></i>
                </div>
              )}
            </label>
          </div>
        </div>
      </div>

      {/* Modal for uploading image */}
      {isModalOpen && (
        <div className="modal-overlay">
          <div className="upload-modal">
            <div className="upload-content">
              <div className="drag-drop-box col-4">
                <span className="plus-icon">+</span>
              </div>
              <p className="upload-img-txt">Drag and drop photo here</p>
              <div className="divider">Or</div>
              <div className="upload-button" onClick={handleDivClick}>
                <i className="fa-solid fa-arrow-up-from-bracket"></i>
                <input type="file" accept="image/png, image/jpeg" ref={fileInputRef} onChange={handleImageChange} style={{ display: "none" }} />
              </div>
              <p className="upload-img-txt">Upload file</p>
              <p className="file-info">PNG, JPG up to 2MB</p>
            </div>
            <button className="close-button" onClick={closeModal}>
              ✖
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

export default ImgUpldChild;

控制台正常输出

FileReader triggered ImgUpldChild.tsx:37
FileReader result type: string ImgUpldChild.tsx:38
FileReader result: data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/4gxUSUNDX1BST0ZJTEUAAQEAAAxEVUNDTQJAAABtbnRyUkdCIFhZWiAH0wAEAAQAAAAAAABhY3NwTVNGVAAAAABDQU5PWjAwOQA....

报错信息

Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node. at removeChild at ImgUpldChild.tsx:41:1

第41行代码为:setTimeout(() => setImage(reader.result as string), 100);

注:组件在CodeSandbox中运行正常,但在项目中报错,补充控制台错误截图:
console errors 1
console errors 2
console errors 3


问题分析与解决

1. 模态框DOM未及时卸载导致引用冲突

选择图片后,你没有关闭模态框就更新图片状态,组件重渲染时,模态框仍处于挂载状态,但FileReader的异步回调+额外的setTimeout会让状态更新脱离当前渲染周期,React协调DOM时会出现节点引用不匹配,触发removeChild错误。

解决:
更新图片状态前先关闭模态框,确保模态框DOM被正确卸载:

if (typeof reader.result === "string") {
  closeModal(); // 先关闭模态框
  setImage(reader.result as string);
}

2. 移除不必要的setTimeout

setTimeout完全是多余的,它会让状态更新延迟,进一步打乱React的DOM协调节奏,直接去掉即可。

3. 检查标签嵌套合法性

你将<div>、<button>等块级元素直接放在<label>内部,虽然HTML允许,但部分浏览器解析时可能出现异常,进而引发React的DOM协调错误。可以把<label>替换为普通<div>,或用<span>包裹文本内容:

<div className="guardian-img-box col-11">
  <span>Father’s Photo</span>
  {/* 原内部内容 */}
</div>

4. 排查项目依赖与版本差异

组件在CodeSandbox正常但项目报错,大概率是项目的React版本或依赖(如babel、webpack)与CodeSandbox不一致。旧版React在异步状态更新的DOM协调上可能存在bug,或项目中存在其他直接操作DOM的库(如jQuery)与React虚拟DOM机制冲突。

解决:

  • 升级React到18.x稳定版本
  • 排查项目中是否有直接操作DOM的代码,避免与React的DOM管理冲突

内容的提问来源于stack exchange,提问作者Darsh. S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:39:58