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!
CodePudding user response:
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>
CodePudding user response:
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!
CodePudding user response:
You dont need the [index] part inside the map so should look like this
<p>{file.name}</p>
Should work now :)
UPDATE FOR MULTIPLE UPLOADS
const handleFile = (e) => {
const newSelectedArray = files;
newSelectedArray.push({
...e.target.files[0],
identifier: e.target.filename //check this please i cant remember what the array name is called for filename. You dont need this yet but once we get the first bit working we can include it in something cool.
});
setFiles(newSelectedArray)
}
Let me know on this one as it was a nightmare for me too so hopefully that will work
CodePudding user response:
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