You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:修复现有逻辑

问题原因

  1. event.target指向的是触发事件的最内层元素,如果你点击的按钮内部有子元素(比如图标、span标签),拿到的target就不是button本身,自然读不到name属性。你应该使用event.currentTarget,它永远指向绑定了事件监听器的元素,也就是你加了onClick的button。
  2. 状态更新逻辑有两个错误:一是没有展开之前的状态对象,会导致其他开关属性被覆盖丢失;二是读取动态属性时错误使用了点语法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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 16:06:08