React同一组件相同prop在不同事件回调中取值不一致问题
问题根因
这个问题和React闭包、Redux异常、组件实例混乱没有任何关系,是HTML原生规则+组件id重复导致的事件触发错位:
- 你在4个
MenuElementSettings组件实例里,给所有表单项都传了固定重复的id:所有复选框id都是openInNewTab,所有名称输入框id都是name,所有链接输入框id都是link。 - Shopify Polaris的表单组件会直接把你传入的id挂载到原生
<input>元素上,同时组件自带的label标签会通过htmlFor属性绑定这个id。按照HTML规范,点击label时浏览器会自动触发页面上第一个id匹配的表单元素的对应事件,和你点的label属于哪个组件实例没有关系。 - 你操作输入框时一般是直接点输入框区域,事件绑定在当前实例的input元素上,所以
handleTextChange能拿到当前实例正确的elementIndex;但操作复选框时大部分人都是点旁边的文字label,浏览器会直接找到页面第一个id为openInNewTab的复选框(也就是elementIndex=0的第一个组件实例里的复选框)触发change事件,所以不管你点哪个实例的复选框,最终执行的都是0号实例的handleCheckboxChange,打印出来的elementIndex永远是0。
你可以马上验证:不要点复选框旁边的文字,精准点击第2、第3个卡片里复选框的小方框本身,控制台打印的elementIndex肯定是对应实例的正确值,不会是0。顺便提一句,你现在的TextField id也是重复的,点对应label的时候会直接聚焦到第一个卡片的输入框,只是你平时直接点输入框操作没察觉到而已。
修复方案
给多实例下的所有表单项传入带elementIndex的全局唯一id即可,不要在可重复渲染的组件里写固定id:
<Stack.Item> <TextField autoComplete="off" id={`name-${elementIndex}`} label="Name" value={newMenuConfigElement.name} onChange={handleTextChange} /> </Stack.Item> <Stack.Item> <TextField autoComplete="off" id={`link-${elementIndex}`} label="Link" value={newMenuConfigElement.link} onChange={handleTextChange} /> </Stack.Item> <Stack.Item> <Checkbox label="Open link in new tab" id={`openInNewTab-${elementIndex}`} checked={newMenuConfigElement.openInNewTab} onChange={handleCheckboxChange} /> </Stack.Item>
如果你的handleTextChange里依赖id做字段映射更新,记得调整匹配逻辑,比如去掉id里的序号后缀再对应字段,更稳妥的方式是直接给回调传明确的字段名,不要依赖DOM的id做业务逻辑判断,避免后续再出类似问题。
内容的提问来源于stack exchange,提问作者Emir Küçükosman
相关产品推荐
相关产品推荐

