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

Next.js多实例文件选择组件异常:图片仅显示于首个实例

问题原因及解决方案

问题根源

所有FileSelector组件内的<input>元素都使用了相同的id="file-selector",同时<label>的htmlFor属性也绑定了这个固定id。由于HTML规范要求页面内的id必须唯一,点击任意组件的标签时,浏览器只会触发第一个匹配该id的输入框(即第一个FileSelector组件的input),导致只有第一个组件的状态会更新,出现选择组件2、3的图片却只在组件1显示的问题。


解决方案

方案1:利用传入的num生成唯一ID

直接通过传入的num参数拼接出唯一的id,确保每个组件的input和label绑定关系唯一:

"use client";

import React from "react";

const FileSelector = ({ num }: { num: string }) => {
  const [filePath, setFilePath] = React.useState<string>("");
  const [fileName, setFileName] = React.useState<string>("");

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
      const value = URL.createObjectURL(file);
      setFilePath(value);
      setFileName(file.name);
    }
  };

  return (
    <div>
      {/* 修改id为唯一值 */}
      <input
        type="file"
        onChange={handleFileChange}
        className="hidden"
        id={`file-selector-${num}`}
      />
      {/* 对应修改htmlFor绑定的id */}
      <label htmlFor={`file-selector-${num}`} className="cursor-pointer">
        <div> 
          {filePath ? (
            <div>
              <img
                className="h-64 w-64 object-contain"
                src={filePath}
                alt={fileName}
              />
            </div>
          ) : (
            <div className="box-border flex h-64 w-64 items-center justify-center border-4 border-white p-4">
              <h1 className="text-2xl font-bold tracking-tight text-white">
                Image {num}
              </h1>
            </div>
          )}
        </div>
      </label>
    </div>
  );
};

export default FileSelector;

方案2:使用React useId生成通用唯一ID(推荐)

如果num存在重复风险,或者需要更通用的唯一标识,可使用React内置的useId钩子生成全局唯一的id:

"use client";

// 导入useId
import React, { useId } from "react";

const FileSelector = ({ num }: { num: string }) => {
  // 生成唯一id
  const fileInputId = useId();
  const [filePath, setFilePath] = React.useState<string>("");
  const [fileName, setFileName] = React.useState<string>("");

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
      const value = URL.createObjectURL(file);
      setFilePath(value);
      setFileName(file.name);
    }
  };

  return (
    <div>
      <input
        type="file"
        onChange={handleFileChange}
        className="hidden"
        id={fileInputId}
      />
      <label htmlFor={fileInputId} className="cursor-pointer">
        <div> 
          {filePath ? (
            <div>
              <img
                className="h-64 w-64 object-contain"
                src={filePath}
                alt={fileName}
              />
            </div>
          ) : (
            <div className="box-border flex h-64 w-64 items-center justify-center border-4 border-white p-4">
              <h1 className="text-2xl font-bold tracking-tight text-white">
                Image {num}
              </h1>
            </div>
          )}
        </div>
      </label>
    </div>
  );
};

export default FileSelector;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:27:19