React map循环绑定点击事件传参时始终获取最后一个元素问题
问题原因
- 所有动态生成的
<input>元素共用了同一个useRef实例attachmentInputRef,ref的current属性会被后续绑定的元素不断覆盖,遍历结束后只会保留数组最后一项(id为4)对应的<input>引用。 - 点击任意按钮调用
handleOpenFilePicker时,实际触发点击的永远是最后一个<input>元素,因此handleFilePicker中拿到的id固定为4。 - 补充小问题:map方法返回了两个同级的
<button>和<input>元素,没有包裹在同一父节点/React.Fragment下,渲染时会报语法错误。
修复方案
方案1:通过id直接定位对应input(实现最简单)
修改点击事件直接传递当前id,不需要依赖ref定位元素:
const [shortlistedIds, setShortlistedIds] = useState([]); const handleOpenFilePicker = (myId) => { // 直接通过id找到对应input触发点击 document.getElementById(`file-input-${myId}`).click(); }; // 业务逻辑中设置id setShortlistedIds(["1", "2", "3", "4"]); // 和onChange绑定的函数命名保持一致即可,原示例属于命名笔误 const handleFilePickerChange = async(myId, e) => { console.log(myId) let uploadFiles = [...e.target.files] const apiRes = await api.createAttachment(myId, uploadFiles) } return( <> {/* 用Fragment包裹同级元素 */} {shortlistedIds.map((myId) => ( <React.Fragment key={myId}> {/* 遍历项需要加唯一key */} <button id={myId} className="attachment-button pull-right" onClick={() => handleOpenFilePicker(myId)} style={{ position: "absolute" }} > click me {myId} </button> <input id={`file-input-${myId}`} {/* 避免和button的id重复 */} type="file" style={{ display: "none" }} name="file" onChange={(e) => {handleFilePickerChange(myId, e);}} multiple /> </React.Fragment> ))} </> )
方案2:使用ref数组存储所有input引用
如果不想用DOM选择器,可以创建ref数组存储每个input的引用:
const [shortlistedIds, setShortlistedIds] = useState([]); // 初始化ref数组,长度和id数组一致 const attachmentInputRefs = useRef([]); const handleOpenFilePicker = (index) => { attachmentInputRefs.current[index].click(); }; setShortlistedIds(["1", "2", "3", "4"]); const handleFilePickerChange = async(myId, e) => { console.log(myId) let uploadFiles = [...e.target.files] const apiRes = await api.createAttachment(myId, uploadFiles) } return( <> {shortlistedIds.map((myId, index) => ( <React.Fragment key={myId}> <button id={myId} className="attachment-button pull-right" onClick={() => handleOpenFilePicker(index)} style={{ position: "absolute" }} > click me {myId} </button> <input ref={el => attachmentInputRefs.current[index] = el} type="file" style={{ display: "none" }} name="file" onChange={(e) => {handleFilePickerChange(myId, e);}} multiple /> </React.Fragment> ))} </> )
内容的提问来源于stack exchange,提问作者Krishna kanth Mundada
相关产品推荐
相关产品推荐

