Home > Back-end >  ReactJS, the index of map function for the onClick event gives me undefined
ReactJS, the index of map function for the onClick event gives me undefined

Time:11-12

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

  • Related