I found a bug, but don't know why this is causing a bug like this.
Inisde a map function, for the onClick event, I gave an arrow function that refers to the index(idx) which is the argument of the map function. Why idx in this code gives me undefined? As of my understanding, due to the nature of closure, this idx should hold the value inside the map function. I've been thinking a long time to figure it out, but in vain.
import React from "react";
import styles from "./FileSelectionList.module.css";
function formatBytes(bytes, decimals = 2, k = 1024) {
let i = Math.floor(Math.log(bytes) / Math.log(k)); // log() in JS is Equivalent to ln() in Mathematics.
if (i > 8) {
bytes = 0;
}
return bytes === 0
? "0 Bytes"
: parseFloat((bytes / Math.pow(k, i)).toFixed(Math.max(0, decimals)))
" "
["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][i];
}
const FileSelectionList = (props) => {
if (props.selectedFiles.length === 0) {
return;
}
const changeFileHandler = (event) => {
const idx = event.target.getAttribute("data-idx");
const file = event.target.getAttribute("data-file");
props.onChangeFile(idx, file);
};
// const removeFileHandler = (event) => {
// const idx = event.target.getAttribute("data-idx");
// props.onRemoveFile(idx);
// };
const removeFileHandler = (event, idx) => {
console.log("idx:", idx);
props.onRemoveFile(idx);
};
return (
<div className={styles["file-selection-result"]}>
<ul className={styles["file-info-list"]}>
{props.selectedFiles.map((file, idx) => {
// console.log("file:", file);
// console.log("idx:", idx);
const id = Math.random().toString();
return (
<li key={id}>
<div className={styles["file-info-detail"]}>
<p>
<strong>
{idx 1}. {file.name}
</strong>
</p>
<p>
<strong>Size: {formatBytes(file.size, 2)}</strong>
</p>
</div>
<div className={styles["buttons-container"]}>
<div className={styles["button-container"]}>
<input
type="file"
data-max-size="104857600"
className={styles["file-change-btn"]}
id={id}
// onChange={changeFileHandler}
// data-idx={idx}
// data-file={file} // string // not a File object
onChange={(event, idx, file) => {
changeFileHandler(idx, file);
}}
></input>
<label htmlFor={id}>C</label>
</div>
<div className={styles["button-container"]}>
<button
className={styles["file-remove-btn"]}
// onClick={removeFileHandler}
// data-idx={idx}
onClick={() => {
console.log(idx); // undefined <------ This is the cause of the bug.
removeFileHandler(idx);
}}
>
R
</button>
</div>
</div>
<div className={styles["thumbnail-container"]}>
<img
className={styles["thumbnail"]}
src={URL.createObjectURL(file)}
alt={file.name}
/>
</div>
</li>
);
})}
</ul>
</div>
);
};
export default FileSelectionList;
CodePudding user response:
I feel the bug is most likely introduced here
<input
type="file"
data-max-size="104857600"
className={styles["file-change-btn"]}
id={id}
// onChange={changeFileHandler}
// data-idx={idx}
// data-file={file} // string // not a File object
onChange={(event, idx, file) => {
changeFileHandler(idx, file);
}}
/>
it uses the local varaible idx which is not likely provided by onChange
// it should be
onChange={(event) => changeFileHandler(idx, file)}
// as (event, idx, ...) => { all params after event, could be undefined }
// try changing this
const removeFileHandler = (event, idx) => {
console.log("idx:", idx);
props.onRemoveFile(idx);
};
//if event param is not used, try removing it
const removeFileHandler = (idx) => {
console.log("idx:", idx);
props.onRemoveFile(idx);
};
and try not using random no as index, use id or index as a last option, cuz it will help with performance with large list, and bugs could be introduced when ids are unstable
const id = Math.random().toString();
Hope it helps
