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
相关产品推荐
相关产品推荐

