ReactJS中onClick事件始终获取最后一个迭代ID的问题排查与修复
嘿,这个问题我太熟了——典型的JavaScript闭包陷阱导致的!让我给你拆解下原因,再给你两个靠谱的修复方案。
问题成因分析
你在timeSlot.map循环里定义的onClick箭头函数,并没有捕获到当前迭代时id的具体数值,而是捕获了id变量的引用。
循环执行过程中,id一直在递增,当循环结束后,id已经变成了最后一次迭代的结果(也就是你看到的70)。当你点击任意按钮时,箭头函数才会真正执行,此时它访问的是id变量最终的引用值,所以所有按钮点击后输出的都是同一个ID。
另外还要提一句:你循环渲染button时没有添加key属性,这会触发React的性能警告,建议补上。
修复方案
这里提供两种可靠的修复方式,你可以根据习惯选择:
方案1:捕获当前迭代的ID到局部变量
在每次迭代时,把当前的id值保存到一个局部变量中,让箭头函数捕获这个局部变量的引用(每次迭代都会创建新的局部变量,所以每个按钮对应的变量值都是独立的):
const renderTableData = () => { let id = 0; return ( <tr> {days.map((val) => ( <td> {timeSlot.map((time, i) => { // 把当前id存入局部变量,确保每个迭代的变量独立 const currentId = id++; if (occupiedSlots().result.includes(currentId + 1)) { return ( <button key={currentId} // 补上React要求的key属性 id={currentId} className="disabledButton" > {time} </button> ); } else { return ( <button key={currentId} id={currentId} className="activeButton" onClick={() => {canBookSlot({id: currentId})}} > {time} </button> ); } })} </td> ))} </tr> ); };
方案2:通过事件对象获取按钮ID
直接在onClick中传递事件对象,从事件目标(按钮本身)读取id属性,彻底避开闭包问题:
首先修改按钮的onClick绑定:
<button key={id} id={id++} className="activeButton" onClick={canBookSlot} // 直接传递函数,不用箭头函数包裹 > {time} </button>
然后修改canBookSlot函数,从事件对象中获取ID:
const canBookSlot = (e) => { // 从事件目标获取按钮的id const currentId = e.target.id; let userDetailsString = localStorage.getItem("userDetails"); const userDetailsObj = JSON.parse(userDetailsString); if(userDetailsObj.canBook !== 0){ // 建议用!==严格相等判断 Axios.post('http://localhost:3001/api/book/week1/ex', { room: userDetailsObj.room, id: currentId }); console.log(currentId); } else { console.log("something's wrong"); } };
这个方案更直接,我们不需要依赖循环中的变量,直接从触发事件的DOM元素上获取需要的信息,也避免了闭包带来的意外问题。
内容的提问来源于stack exchange,提问作者Max Andersson
相关产品推荐
相关产品推荐

