React useState切换对象内布尔属性时如何识别onClick事件触发源
问题描述
这可能是个很基础的问题,只是我暂时还没找到对应的解决方案。
我希望使用useState管理存储了onChange和onClick事件对应状态的对象。
对于onChange事件,虚拟DOM会提供event.target.name和event.target.value属性,我们可以很轻松地识别事件需要修改的目标参数。
但onClick事件的event.target上没有这两个属性,无法直接关联到目标元素。
我该如何识别触发onClick事件的标签,从而在包含多个布尔参数的状态对象中,指定需要修改的对应参数呢?
以下是我编写的尽可能简单完整的示例代码:
import React, { useState, useEffect } from 'react'; const initialState = { switches: { menuOpen: false, modalOpen: false, }, fields: { username: '', password: '', }, }; export default function Header(props) { const [changeStateObj, setChangeStateObj] = useState(initialState.fields); const [toggleStateObj, setToggleStateObj] = useState(initialState.switches); useEffect(() => { console.log(changeStateObj, toggleStateObj); }, [changeStateObj, toggleStateObj]); const changeHandler = (event) => { let name = event.target.name; // 这里可以正常拿到属性值 let value = event.target.value; setChangeStateObj((values) => ({ ...values, [name]: value })); // 所以该逻辑可以正常运行 }; const clickHandler = (event) => { let name = event.target.name // 这里拿不到对应属性 setToggleStateObj((prevState) => ({ [name]: !prevState.name })); // 逻辑无法生效 }; return ( <div> <label htmlFor="username"> 用户名 <input type="text" name="username" onChange={changeHandler} /> </label> <label htmlFor="password"> 密码 <input type="password" name="password" onChange={changeHandler} /> </label> <button name="modalOpen" onClick={clickHandler}> 打开弹窗 </button> <button name="menuOpen" onClick={clickHandler}> 打开菜单 </button> </div> ); }
解决方案
button标签定义的name属性本身是可以通过事件对象读取到的,你的代码无法生效是两个写法问题导致的,修复后即可正常运行,也可以选择更通用的传参方案实现需求:
方案1:修复现有逻辑
问题原因
event.target指向的是触发事件的最内层元素,如果你点击的按钮内部有子元素(比如图标、span标签),拿到的target就不是button本身,自然读不到name属性。你应该使用event.currentTarget,它永远指向绑定了事件监听器的元素,也就是你加了onClick的button。- 状态更新逻辑有两个错误:一是没有展开之前的状态对象,会导致其他开关属性被覆盖丢失;二是读取动态属性时错误使用了点语法
prevState.name,应该用方括号prevState[name]才能读取到name变量对应的属性值。
修复后的clickHandler代码
const clickHandler = (event) => { const name = event.currentTarget.name; setToggleStateObj((prevState) => ({ ...prevState, [name]: !prevState[name] })); };
方案2:直接给事件处理函数传参(更通用)
不需要依赖DOM的name属性,绑定事件时直接通过箭头函数传入要切换的状态名,避免事件冒泡带来的target异常问题,适配性更强:
调整clickHandler
const clickHandler = (toggleName) => { setToggleStateObj((prevState) => ({ ...prevState, [toggleName]: !prevState[toggleName] })); };
调整按钮绑定逻辑
<button onClick={() => clickHandler('modalOpen')}> 打开弹窗 </button> <button onClick={() => clickHandler('menuOpen')}> 打开菜单 </button>
内容的提问来源于stack exchange,提问作者Avery Freeman
相关产品推荐
相关产品推荐

