无法根据元素类型有条件地更改具有设置状态的样式

Cannot change style with set state conditionally based on type of element

我试图在您使用 changeActivityStyleBasedOnZone 函数单击区域按钮时更改 activity 按钮的颜色。例如,如果我单击类型为“浓度”的区域按钮,我想将 activity 按钮的颜色更改为与类型为“浓度”的按钮相同的颜色。现在,当您单击区域按钮时,所有 activity 按钮都会改变颜色。现在我有一个功能,如果你点击一个 activity 按钮,它会根据 activity 的类型改变颜色,这是我想保留的东西。如何只使与单击区域按钮类型相同的按钮更改颜色而不影响其他 activity 按钮?我还尝试测试按类型过滤活动数组,然后通过过滤数组进行映射以仅在过滤数组上设置状态,但也许这是错误的方法或者我做错了,因为映射似乎不起作用.

import React, { useState } from 'react';

const Game = (activityType) => {
 const [activityStyle, setActivityStyle] = useState("activity");
 const [zoneClicked, setZoneClicked] = useState(false);
 const [clickedActivityIndex, setClickedActivityIndex] = useState(-1);

 const zones = [
    {id: 1, name: "Concentration", styleType: "concentration-zone", type: "concentration" },
    {id: 2, name: "Communication", styleType: "communication-zone", type: "communication"},
    {id: 3, name: "Collaboration", styleType: "collaboration-zone",  type: "collaboration"},
    {id: 4, name: "Chill Out", styleType: "chill-out-zone", type: "chillout"},
    {id: 5, name: "Camp", styleType: "camp-zone", type: "camp"}
   ]

 const activities = [
    {id: 1, name: "Code", type: "concentration"},
    {id: 2, name: "Teams Meeting", type: "communication"},
    {id: 3, name: "Make a phone call", type: "camp"},
    {id: 4, name: "Work shops with colleagues", type: "collaboration"},
    {id: 5, name: "Coffee break", type: "chillout"},
    {id: 6, name: "Lively discussions & brainstorming", type: "collaboration"},
   ]

 const changeActivityStyle = (activityType, index) => {
    setClickedActivityIndex(index);
     if (activityType === "concentration") {
         setActivityStyle("activity-concentration");
         setClickedActivityIndex(0) ;
       }
     if (activityType === "communication") {
         setActivityStyle("activity-communication");
     }
     if (activityType === "camp") {
         setActivityStyle("activity-camp");
     }
     if (activityType === "chillout") {
         setActivityStyle("activity-chill-out");
     } 
     if (activityType === "collaboration") {
         setActivityStyle("activity");
     }
     return;
 };

 const changeActivityStyleBasedOnZone = (zoneType) => {
     setZoneClicked(true);
     if (zoneType === "concentration") {
         const concentrationActivities = activities.filter(activity => activity.type === "concentration");
         concentrationActivities.map((ca) => {
            setActivityStyle("activity-concentration");
         }); 
        }
         
     if (zoneType === "communication") {
         setActivityStyle("activity-communication");
     }
     if (zoneType === "camp") {
         setActivityStyle("activity-camp");
     }
     if (zoneType === "chillout") {
         setActivityStyle("activity-chill-out");
     }
     if (zoneType === "collaboration") {
         setActivityStyle("activity");
     }
     return;
 }
return (
        <>
            <section className="header"><h2>Click on an activity box to see which area it belongs to</h2></section>
            <section className="game-area">
                <div className="activity-zone-container">
                    <div className="zone-container">
                        {zones.map((zone =>
                            <button 
                                className="zone" 
                                id={zone.styleType} 
                                key={zone.id}
                                zoneType={zone.type}
                                onClick={() => changeActivityStyleBasedOnZone(zone.type, 
                                 activityType)}
                                >
                                <p>{zone.name}</p>
                            </button>
                         ))}
                    </div>
                    <div className="activity-container">
                        {activities.map((activity, index) => 
                            <button 
                                className={clickedActivityIndex === index | zoneClicked === true ? activityStyle: 'activity'} 
                                onClick={() => changeActivityStyle(activity.type, index)} 
                                key={activity.id}
                                activityType={activity.type}>
                                <p>{activity.name}</p>
                            </button>
                            )}
                    </div>        
                </div>
            </section>
        </>
     );
   };

CSS

#concentration-zone {
  background-color: orange;
}

#communication-zone {
  background-color: yellow;
}

#communication-zone p {
  color: black;
}

#collaboration-zone {
  background-color: #3260a8;
}

#chill-out-zone {
  background-color: pink;
}

#chill-out-zone p {
  color: black;
}

#camp-zone {
  background-color: green;
}

.activity {
  background-color: #3260a8;
  margin: 17px;
  display: flex;
  justify-content: center;
  cursor: pointer;
  width: 140px;
  height: 87px;
}

.activity-concentration {
  background-color: orange;
  margin: 17px;
  display: flex;
  justify-content: center;
  color: white;
  width: 140px;
  height: 87px;
}

.activity-communication {
  background-color: yellow;
  margin: 17px;
  display: flex;
  justify-content: center;
  width: 140px;
  height: 87px;
}

.activity-chill-out {
  background-color: pink;
  margin: 17px;
  display: flex;
  justify-content: center;
  width: 140px;
  height: 87px;
}

.activity-camp {
  background-color: green;
  margin: 17px;
  display: flex;
  justify-content: center;
  color: white;
  width: 140px;
  height: 87px;
}

试试这个 link 并告诉我应用程序是否应该这样工作。 https://growingillfatedrate.pskath1.repl.co/

这是工作代码

import React,{ useState } from 'react';

const activities = [
    {id: 1, name: "Code", type: "concentration"},
    {id: 2, name: "Teams Meeting", type: "communication"},
    {id: 3, name: "Make a phone call", type: "camp"},
    {id: 4, name: "Work shops with colleagues", type: "collaboration"},
    {id: 5, name: "Coffee break", type: "chill-out"},
    {id: 6, name: "Lively discussions & brainstorming", type: "collaboration"},
];


 const zones = [
    {id: 1, name: "Concentration", styleType: "concentration-zone", type: "concentration" },
    {id: 2, name: "Communication", styleType: "communication-zone", type: "communication"},
    {id: 3, name: "Collaboration", styleType: "collaboration-zone",  type: "collaboration"},
    {id: 4, name: "Chill Out", styleType: "chill-out-zone", type: "chill-out"},
    {id: 5, name: "Camp", styleType: "camp-zone", type: "camp"}
];






const Game = () => {

 const [activityStyle, setActivityStyle] = useState("activity");
 const [zoneClicked, setZoneClicked] = useState(false);
 const [clickedActivityIndex, setClickedActivityIndex] = useState(-1);


 const changeActivityStyle = (activityType, index) => {
    setClickedActivityIndex(index);
     if (activityType === "concentration") {
         setActivityStyle("concentration");
         setClickedActivityIndex(0) ;
      }

     if (activityType === "communication") {
         setActivityStyle("communication");
     }
     if (activityType === "camp") {
         setActivityStyle("camp");
     }
     if (activityType === "chillout") {
         setActivityStyle("chill-out");
     } 
     if (activityType === "collaboration") {
         setActivityStyle("collaboration");
     }
     
     if (activityType === "chill-out") {
         setActivityStyle("chill-out");
     }
     return;
 };

 const changeActivityStyleBasedOnZone = (zoneType) => {
     setZoneClicked(true);
     if (zoneType === "concentration") {
        setActivityStyle("concentration")
      }
         
     if (zoneType === "communication") {
         setActivityStyle("communication");
     }
     if (zoneType === "camp") {
         setActivityStyle("camp");
     }
     if (zoneType === "chill-out") {
         setActivityStyle("chill-out");
     }
     if (zoneType === "collaboration") {
         setActivityStyle("collaboration");
     }
     return;
 }
return (
        <>
            <section className="header"><h2>Click on an activity box to see which area it belongs to</h2></section>
            <section className="game-area">
                <div className="activity-zone-container">
                    <div className="zone-container">
                        {zones.map((zone =>
                            <button 
                                className={zone.type} 
                                id={zone.styleType} 
                                key={zone.id}
                                zoneType={zone.type}
                                onClick={() => changeActivityStyleBasedOnZone(zone.type)}
                                >
                                <p>{zone.name}</p>
                            </button>
                         ))}
                    </div>
                    <div className="activity-container">
                        {activities.map((activity, index) => 
                            <button 
                                className={activityStyle == activity.type ? activityStyle: '' } 
                                onClick={() => { changeActivityStyle(activity.type, index) }} 
                                key={activity.id}
                                activityType={activity.type}>
                                <p>{activity.name}</p>
                            </button>
                            )}
                    </div>        
                </div>
            </section>
        </>
     );
};

还有相同的 repl link 您可以添加您的样式并按您的方式进行测试。 https://replit.com/@pskath1/GrowingIllfatedRate?v=1

这里有很多问题。我将尝试以合理的顺序解决它们,然后在最后提供示例代码。

问题

1.所有按钮都因为这一行而变色:

className={clickedActivityIndex === index | zoneClicked === true ? activityStyle: 'activity'}

如果zoneClickedtrue,存储在activityStyle中的class将应用于所有按钮。同时,一旦调用 changeActivityStyleBasedOnZonezoneClicked 就会设置为 true

const changeActivityStyleBasedOnZone = (zoneType) => {
     setZoneClicked(true);
...
}

2.changeActivityStylechangeActivityStyleBasedOnZone相互冲突

它们都更改 activityStyle,因此当前值将应用于具有匹配条件的按钮并覆盖先前的 class 值。这在逻辑上是混乱的,让人不清楚 changeActivityStyle 的意义是什么。我的假设是您想对所选区域应用不同的样式 activity,独立于所选区域样式。

3. changeActivityStylechangeActivityStyleBasedOnZone 中的 if 块是不必要的,会使代码复杂化。

这个特定的块有问题。它多次将相同的值应用于 activityStyle。我从我的解决方案中完全删除了它,但我想让你知道这一点。

if (zoneType === "concentration") {
      const concentrationActivities = activities.filter(
        (activity) => activity.type === "concentration"
      );
      concentrationActivities.map((ca) => {
        setActivityStyle("activity-concentration");
      });
    }

4. zoneTypeactivityType 无效 html button 属性。

使用 data- 属性创建自定义属性。名称必须全部小写。例如data-activity-typedata-zone-type


解决方法

正如我所说,我不完全确定你的目标,而且我没有你的 CSS,所以你需要根据你的用例进行调整。也就是说,我认为它会让你接近。

这里是 CodeSandbox 的完整示例。我添加了一个 table 来显示状态值。

首先,我改变了changeActivityStylechangeActivityStyleBasedOnZone

const changeActivityStyle = (index) => {
    setClickedActivityIndex(index);
  };

  const changeActivityStyleBasedOnZone = (zone) => {
    setZoneClicked(zone);
    return;
  };

您会注意到这意味着 zoneClicked 现在存储整个 zone 对象。因此,将 useState 挂钩更改为:

const [zoneClicked, setZoneClicked] = useState({});

并且区域按钮 onClick 更改为:

onClick={() => changeActivityStyleBasedOnZone(zone)}

然后我像这样更改了 activity 按钮 className

<button
    className={
        `${activity.type === zoneClicked.type ? zoneClicked.styleType :"activity"} 
        ${clickedActivityIndex === index ? "selected" : ""}`
    }
    onClick={(e) => changeActivityStyle(index)}
    key={activity.id}
    data-activity-type={activity.type}
    >

使用模板文字,我们可以根据两种条件应用两种不同的 classes,一种与选定区域相关,一种与选定区域相关 activity。

由于 zoneClicked 现在存储整个区域,我只是将所选区域的 styleType 应用为 class 名称。

如果选定的 activity 索引匹配,我会应用额外的 class 来突出显示选定的按钮。在这种情况下,class 只是删除边框,但您可以应用任何您想要的样式。请注意 selected class 中的 !important 运算符 - 这可确保区域 class 在以后应用时不会覆盖它。