I've got a Next.js component that I'm loading on a form 3 times, and passing a number to each one. The component is basically just a Input for a file. So I select an image, and then in theory should display that image in the component that picked it. But whatever image is picked in component 2 or 3, the image only shows in component 1. And I'm at a loss as to why. I recognise that I must be missing something really straightforward here. But I'm missing it. I've cut this code down to as minimal as possible to reproduce the issue.
Here is the Form:
"use client";
import FileSelector from "./file_selector";
export const SimpleForm = () => {
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-center gap-4 p-4">
<FileSelector num="1" />
<FileSelector num="2" />
<FileSelector num="3" />
</div>
</div>
);
};
Here is the component (file_selector):
"use client";
import React from "react";
import { ImgBox, ShowImg } from "./img_options";
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) {
console.log("file is ", file);
const value = URL.createObjectURL(file);
setFilePath(value);
setFileName(file.name);
}
};
return (
<div>
<input
type="file"
onChange={handleFileChange}
className="hidden"
id="file-selector"
/>
<label htmlFor="file-selector" className="cursor-pointer">
{/* I had this div and the one below in separate components, but added them here for simplicity. */}
<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;
So, if I select an image with either Image 2 or Image 3, both of those set Image 1. Image 1 also sets Image 1. All 3 Image divs show the correct number.
I've got a Next.js component that I'm loading on a form 3 times, and passing a number to each one. The component is basically just a Input for a file. So I select an image, and then in theory should display that image in the component that picked it. But whatever image is picked in component 2 or 3, the image only shows in component 1. And I'm at a loss as to why. I recognise that I must be missing something really straightforward here. But I'm missing it. I've cut this code down to as minimal as possible to reproduce the issue.
Here is the Form:
"use client";
import FileSelector from "./file_selector";
export const SimpleForm = () => {
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-center gap-4 p-4">
<FileSelector num="1" />
<FileSelector num="2" />
<FileSelector num="3" />
</div>
</div>
);
};
Here is the component (file_selector):
"use client";
import React from "react";
import { ImgBox, ShowImg } from "./img_options";
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) {
console.log("file is ", file);
const value = URL.createObjectURL(file);
setFilePath(value);
setFileName(file.name);
}
};
return (
<div>
<input
type="file"
onChange={handleFileChange}
className="hidden"
id="file-selector"
/>
<label htmlFor="file-selector" className="cursor-pointer">
{/* I had this div and the one below in separate components, but added them here for simplicity. */}
<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;
So, if I select an image with either Image 2 or Image 3, both of those set Image 1. Image 1 also sets Image 1. All 3 Image divs show the correct number.
Share Improve this question edited Feb 5 at 7:31 DarkBee 15.6k8 gold badges71 silver badges116 bronze badges asked Feb 5 at 5:52 PrimitivePrimitive 214 bronze badges1 Answer
Reset to default 2In this label:
<label htmlFor="file-selector" className="cursor-pointer">
You have same htmlFor
attribute for each instance as a result its binding it with wrong input.
Solution:
Make the htmlFor attribute unique
so it binds with that specific instance like this:
<label htmlFor={`file-selector-${num}`} className="cursor-pointer">
This ensures that each label correctly binds to its corresponding file input, and images will be set accordingly.