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

为何两个近乎相同的Toggle函数仅一个能修改React状态属性?

问题描述

我编写的ToggleDisplayMenu函数可正常切换isDisplayMenu状态,但用完全相同逻辑实现的ToggleMelkesjef和ToggleOrdenselev函数,点击对应按钮时虽会触发调用,isMelkesjef和isOrdenselev的属性值却始终无法改变。

相关函数代码:

//Function to toggle displaymenu
function ToggleDisplayMenu(name) {
  setStudents(
    students.map((student) =>
      student.name === name
        ? { ...student, isDisplayMenu: !student.isDisplayMenu }
        : student
    )
  );
}
//Function to toggle ordenselev
function ToggleOrdenselev(name) {
  setStudents(
    students.map((student) =>
      student.name === name
        ? { ...student, isOrdenselev: !student.isOrdenselev }
        : student
    )
  );
}
//Function to toggle melkesjef
function ToggleMelkesjef(name) {
  setStudents(
    students.map((student) =>
      student.name === name
        ? { ...student, isMelkesjef: !student.isMelkesjef }
        : student
    )
  );
}

完整代码:

import "./styles.css";
import { useState } from "react";

let studentnames = [
  {
    name: "Colin",
    birthday: 1.01
  },
  {
    name: "Eskil",
    birthday: 1.01
  },
  {
    name: "Ane",
    birthday: 1.01
  },
  {
    name: "Adrian",
    birthday: 1.01
  },
  {
    name: "Eline",
    birthday: 1.01
  },
  {
    name: "Aurora",
    birthday: 1.01
  },
  {
    name: "Mia",
    birthday: 1.01
  },
  {
    name: "Ella",
    birthday: 1.01
  },
  {
    name: "Magnus",
    birthday: 1.01
  },
  {
    name: "Marin",
    birthday: 1.01
  }
];
studentnames.map(
  (student) => (
    (student.isMelkesjef = false),
    (student.isOrdenselev = false),
    (student.isDisplayMenu = false)
  )
);

function Studentlist(props) {
  const { studentnames } = props;

  const [students, setStudents] = useState(studentnames);

  //Function to toggle displaymenu
  function ToggleDisplayMenu(name) {
    setStudents(
      students.map((student) =>
        student.name === name
          ? { ...student, isDisplayMenu: !student.isDisplayMenu }
          : student
      )
    );
  }
  //Function to toggle ordenselev
  function ToggleOrdenselev(name) {
    setStudents(
      students.map((student) =>
        student.name === name
          ? { ...student, isOrdenselev: !student.isOrdenselev }
          : student
      )
    );
  }
  //Function to toggle melkesjef
  function ToggleMelkesjef(name) {
    setStudents(
      students.map((student) =>
        student.name === name
          ? { ...student, isMelkesjef: !student.isMelkesjef }
          : student
      )
    );
  }
  //Return the actual html element
  return students.map((student) => (
    <div
      className="studentbox"
      id={student.name}
      onClick={() => ToggleDisplayMenu(student.name)}
    >
      {student.isDisplayMenu ? (
        <>
          <button onClick={() => ToggleMelkesjef(student.name)}>
            {student.isMelkesjef ? "Fjern melkesjef" : "Bli melkesjef"}
          </button>
          <button onClick={() => ToggleOrdenselev(student.name)}>
            {student.isOrdenselev ? "Fjern ordenselev" : "Bli Ordenselev"}
          </button>
          <button>{student.isFravær ? "Fjern fravær" : "Bli fravær"}</button>
        </>
      ) : (
        <>
          <h2>{student.name}</h2>
          <h3>{student.birthday}</h3>
        </>
      )}
    </div>
  ));
}

export default function App() {
  return (
    <div className="container">
      <Studentlist studentnames={studentnames}></Studentlist>
    </div>
  );
}

通过console.log和三元运算符验证,除isMelkesjef和isOrdenselev状态不更新外,其他逻辑均正常,三个函数逻辑几乎完全一致。


问题原因及修复方案

核心原因

按钮的点击事件会冒泡到父元素<div className="studentbox">,导致每次点击按钮时,ToggleMelkesjef/ToggleOrdenselev刚更新完状态,ToggleDisplayMenu就被触发,把isDisplayMenu切回false,菜单直接收起,视觉上看起来状态没变化,实际上状态更新后又被重置了。

修复步骤

1. 阻止按钮点击事件冒泡

给按钮的点击事件添加event.stopPropagation(),避免触发父元素的点击逻辑:

<button onClick={(e) => {
  e.stopPropagation();
  ToggleMelkesjef(student.name);
}}>
  {student.isMelkesjef ? "Fjern melkesjef" : "Bli melkesjef"}
</button>
<button onClick={(e) => {
  e.stopPropagation();
  ToggleOrdenselev(student.name);
}}>
  {student.isOrdenselev ? "Fjern ordenselev" : "Bli Ordenselev"}
</button>
<button onClick={(e) => {
  e.stopPropagation();
  // 补充对应的ToggleFravær函数逻辑
}}>
  {student.isFravær ? "Fjern fravær" : "Bli fravær"}
</button>

2. 优化状态初始化逻辑

原代码直接修改了原始studentnames数组的对象,可能引发不必要的副作用。建议在useState中创建新对象初始化状态:

const [students, setStudents] = useState(
  studentnames.map(student => ({
    ...student,
    isMelkesjef: false,
    isOrdenselev: false,
    isDisplayMenu: false,
    isFravær: false // 补充isFravær的初始状态
  }))
);

这样可避免修改原始数组,保持状态的独立性。


内容的提问来源于stack exchange,提问作者Vegard Blix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:17:19