First, please check out my code.
There might be some misspell! ( I rewrote my code )
const test = () => {
const [files, setFiles] = useState([]);
const handleFile = (e) => {
for(let i=0; i<e.target.files.length; i++){
setFiles([...files, e.target.files[i]
}
}
return (
{
files.map((file, index) => (
<div key={index}>
<p> {file[index].name} </p>
<button> Delete </button>
</div>
))
}
<label onChange={handleFile}>
<input type='file' mutiple /> Attach File
</label>
)
}
When I render with this code, makes errors,
TypeError: Cannot read Properties of undefined (reading 'name')
{file[index].name}
like this.
When I delete .name, only buttons are being rendered. ( as I didn't specify what to render of file's property. )
Moreover, I'm trying to render multiple files at once. As I set my input type as multiple, I can select multiple files when I choose to upload things.
However, even though I selected two or three, It only renders just one.
I hope my explanation describes my situation well. If you have any questions, please ask me!
I'm looking forward to hearing from you!
If you update the same state multiple time in the same handler function only the last call will work for performance issue. You have to change your onChange handler to something like:
const handleFile = (e) => {
const newFiles = []
for(let i = 0; i < e.target.files.length; i++){
newFiles.push(e.target.files[i])
}
setFiles(newFiles)
}
also as mentioned in another answer, change the "name" line to this:
<p>{file.name}</p>
For anyone who has the same trouble as me, Here is a stopgap.
const [files, setFiles] = useState([]);
const handleFile = (e) => {
setFiles([...files, e.target.files[0], e.target.files[1], e.target.files[2]])
if(e.target.files[1] == null) {
setFiles([...files, e.target.files[0]])
} if (e.target.files[1] && e.target.files[2] == null) {
setFiles([...files, e.target.files[0], e.target.files[1]])
}
};
Using conditional statement, you can control the index of files. However, I still don't know what is the other way to deal with the problem.
Anyway, I hope my answer helps you some!
I am not sure if i am missing out something, but I think looping like this is redundant when instead you can simply do
const handleFile = (e) => {
setFiles(e.target.files)
}
Also, when you want to access the previous state value you should probably access the previous state value by using a callback function inside setFiles like this
for(let i=0; i<e.target.files.length; i++){
setFiles((prevfiles)=>[...prevFiles,e.target.files[i]])
}
EDIT: I am also mentioning a fix not included in the original answer since it had already been stated by @Matt at the time of posting.I am editing this answer only for the sake of providing the complete answer
file[index].name had to be changed to file.name