React中map函数onClick事件获取idx为undefined的问题求助
问题:map循环中onClick箭头函数引用idx返回undefined
在React组件的map循环内部,为按钮的onClick事件定义箭头函数时,引用map回调的参数idx(索引),但实际打印idx为undefined。按闭包特性,这个idx应该能保留当前循环的索引值,排查许久未找到原因。
相关代码
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;
问题原因
问题出在input的onChange箭头函数参数定义上:
onChange={(event, idx, file) => { changeFileHandler(idx, file); }}
这里重新声明了idx和file作为箭头函数的参数,会覆盖map回调函数作用域里的idx变量。由于React的onChange事件只会传递event一个参数,箭头函数里的idx和file会被赋值为undefined,而这个局部变量的作用域覆盖了整个map回调,导致后面按钮onClick里引用的idx指向的是这个未赋值的局部变量,最终打印出undefined。
另外,removeFileHandler的调用也存在问题:该函数定义为接收event和idx两个参数,但调用时只传了idx,导致event参数接收到的是idx的值,而idx参数会是undefined。
修复方案
1. 修正onChange的参数名,避免变量覆盖
把onChange箭头函数的参数名改成不与外部变量重名的名称,同时调整changeFileHandler的定义以正确接收参数:
// 修改changeFileHandler const changeFileHandler = (idx, file) => { props.onChangeFile(idx, file); }; // 修改input的onChange <input type="file" data-max-size="104857600" className={styles["file-change-btn"]} id={id} onChange={(event) => { // 直接传递外部的idx和file,不重名 changeFileHandler(idx, file); }} ></input>
2. 修正removeFileHandler的调用和定义
如果不需要event参数,直接简化removeFileHandler:
// 修改removeFileHandler const removeFileHandler = (idx) => { console.log("idx:", idx); props.onRemoveFile(idx); }; // 修改按钮的onClick <button className={styles["file-remove-btn"]} onClick={() => { console.log(idx); removeFileHandler(idx); }} > R </button>
3. 优化key的使用(可选但推荐)
当前用Math.random().toString()作为列表项的key会导致每次渲染都生成新的key,引发不必要的组件重渲染。建议改用文件的唯一标识作为key,比如:
<li key={`${file.name}-${file.size}-${idx}`}>
内容的提问来源于stack exchange,提问作者hansf14
相关产品推荐
相关产品推荐

