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