为何两个近乎相同的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
相关产品推荐
相关产品推荐

