AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79597088
Accepted
Ninety9Balloons
Ninety9Balloons
Asked: 2025-04-29 02:27:33 +0800 CST2025-04-29 02:27:33 +0800 CST 2025-04-29 02:27:33 +0800 CST

如何更新已过滤数组内的对象?

  • 772

我正在做这个前端导师挑战,大部分功能都已实现。我可以根据数据的isActive属性进行过滤,根据它们是否处于活动状态来显示正确的项目。但我搞不清楚如何更新单个项目的isActive状态,以及如何在切换时重新渲染应用,以便将项目移动到正确的过滤器中。

以下是代码App.jsx:

function App() {
  const [data, setData] = useState([]);
  const [filteredData, setFilteredData] = useState(data);
  const [activeFilter, setActiveFilter] = useState("All");

  // Fetch and set the data.
  useEffect(() => {
    fetch("../data.json")
      .then((response) => response.json())
      .then((data) => setData(data))
      .catch((error) => console.error("error", error));
  }, []);

  // Filter the data
  useEffect(() => {
    if (activeFilter === "All") {
      setFilteredData(data);
    } else if (activeFilter === "Active") {
      setFilteredData(data.filter((item) => item.isActive === true));
    } else {
      setFilteredData(data.filter((item) => item.isActive === false));
    }
  }, [activeFilter, data]);

  return (
    <div className="w-full h-full bg-linear-to-b from-[#040918] to-[#091540] py-6 px-3 flex flex-col text-white">
      {/* Header */}
      <Header />

      {/* Options */}
      <Options activeFilter={activeFilter} setActiveFilter={setActiveFilter} />

      {/* Cards */}
      {filteredData &&
        filteredData.map((item) => (
          <Card
            logo={item.logo}
            name={item.name}
            description={item.description}
            isActive={item.isActive}
            key={item.name}
            setFilteredData={setFilteredData}
            filteredData={filteredData}
          />
        ))}
    </div>
  );
}

这是Card.jsx带有拨动开关的:

const Card = ({
  logo,
  name,
  description,
  isActive,
  filteredData,
  setFilteredData,
}) => {
  const [activeState, setActiveState] = useState(isActive);

  function handleClick() {
    setActiveState(!activeState);
  }

  return (
    <div className="bg-neutral-700 p-4 rounded-xl border border-neutral-600 mt-4">
      <div className="flex items-start gap-4">
        {/* Logo */}
        <img src={logo} alt="Extension Image" />

        {/* Name and Description */}
        <div className="flex flex-col gap-2 mb-8">
          <h2 className="font-semibold text-xl">{name}</h2>
          <p className="text-sm font-light">{description}</p>
        </div>
      </div>

      {/* Remove Button */}
      <div className="flex justify-between items-center">
        <div className="border border-neutral-600 rounded-full px-3 py-1 flex items-center justify-center">
          <button>Remove</button>
        </div>

        {/* Is Active Toggle */}
        <div className="flex items-center justify-center">
          <label
            htmlFor={`${name}Toggle`}
            className="flex items-center cursor-pointer "
          >
            <div className="relative">
              <input
                id={`${name}Toggle`}
                type="checkbox"
                className="sr-only"
                onClick={handleClick}
              />
              <div
                className={`flex items-center ${
                  activeState ? "bg-red-400 " : "bg-gray-600 "
                } w-11 h-6 rounded-full transition-all px-[2px]`}
              >
                <div
                  className={`bg-white w-5 h-5 rounded-full ${
                    activeState ? "translate-x-5" : "translate-x-0"
                  } transition-all`}
                ></div>
              </div>
            </div>
          </label>
        </div>
      </div>
    </div>
  );
};

我试图在卡片handleclick函数里找到同样的方法,将特定卡片的名称与物品的名称匹配,filteredData然后……翻转它的isActive状态?我不知道该怎么做,我甚至不确定这是不是最好的方法。

javascript
  • 2 2 个回答
  • 63 Views

2 个回答

  • Voted
  1. Best Answer
    David
    2025-04-29T03:07:14+08:002025-04-29T03:07:14+08:00

    看起来状态被复制了。父组件维护着列表项和过滤器的状态,并将isActive状态值传递给每个子组件:

    isActive={item.isActive}
    

    然而,子组件随后将该值复制到其内部管理的状态中:

    const [activeState, setActiveState] = useState(isActive);
    

    更新该状态对父组件中的列表没有影响。

    不要在子组件中跟踪重复的状态,而是将回调函数传递给子组件,该函数会更新父组件中的状态。例如,假设父组件有以下内容:

    const toggleActiveItem = (itemName) => {
      setData(data.map(d => (
        d.name === itemName ? {
          ...d,
          isActive: !d.isActive
        } : d
      )));
    };
    

    (注意:这当然是自由的,没有用您的数据进行测试。但上述的总体目标是将状态更新为一个新的项目数组,其中为isActive与指定项目匹配的项目切换标志。)

    然后将其传递给子组件以更新该状态:

    isActive={item.isActive}
    toggleIsActive={toggleActiveItem}
    

    然后子组件可以useState完全删除它并调用传递给它的回调函数:

    const Card = ({
      logo,
      name,
      description,
      isActive,
      toggleIsActive,
      filteredData,
      setFilteredData,
    }) => {
      function handleClick() {
        toggleIsActive(name);
      }
    
      //...
    

    这样,父状态就会更新,父组件和相关子组件会使用新状态重新渲染。

    • 2
  2. Drew Reese
    2025-04-29T03:21:24+08:002025-04-29T03:21:24+08:00

    问题

    您已经实现了至少几个 React 反模式:

    1. filteredData是派生的“状态”,例如,从data和activeFilter真值源状态派生而来,因此filteredData不应同时是 React 状态。您应该在渲染时计算过滤后的值,或将其值记忆起来。请记住,实现useState-useEffect耦合也是一种反模式,在几乎 100% 的用例中,这种耦合应该用useMemo钩子代替。
    2. 该Card组件无法正确更新data父组件中的可靠来源。它传递了一个isActiveprop,但还应该传递一个回调函数来处理父组件中状态的更新。

    解决方案建议

    • 过滤状态data以计算得出的过滤数据值。
    • 创建一个切换活动处理程序来更新data状态并将其传递Card给filteredData状态和状态更新器(将被删除)。

    例子:

    function App() {
      const [data, setData] = useState([]);
      const [activeFilter, setActiveFilter] = useState("All");
    
      // Fetch and set the data.
      useEffect(() => {
        fetch("../data.json")
          .then((response) => response.json())
          .then((data) => setData(data))
          .catch((error) => console.error("error", error));
      }, []);
    
      const filteredData = useMemo(() => {
        return data.filter(item => {
          if (activeFilter === "Active") {
            return item.isActive;
          }
          return true;
        });
      }, [data, activeFilter]);
    
      const toggleActiveByIndex = (index) => () => {
        setData(data => data.map((item, i) => i === index
          ? { ...item, isActive: !item.isActive }
          : item
        ));
      };
    
      return (
        <div className="w-full h-full bg-linear-to-b from-[#040918] to-[#091540] py-6 px-3 flex flex-col text-white">
          {/* Header */}
          <Header />
    
          {/* Options */}
          <Options activeFilter={activeFilter} setActiveFilter={setActiveFilter} />
    
          {/* Cards */}
          {filteredData.map((item, index) => (
            <Card
              key={item.name}
              item={item}
              toggleActive={toggleActiveByIndex(index)}
            />
          ))}
        </div>
      );
    }
    
    const Card = ({ item, toggleActive }) => {
      const { logo, name, description, isActive } = item;
    
      function handleClick() {
        toggleActive();
      }
    
      return (
        <div className="bg-neutral-700 p-4 rounded-xl border border-neutral-600 mt-4">
          <div className="flex items-start gap-4">
            {/* Logo */}
            <img src={logo} alt="Extension Image" />
    
            {/* Name and Description */}
            <div className="flex flex-col gap-2 mb-8">
              <h2 className="font-semibold text-xl">{name}</h2>
              <p className="text-sm font-light">{description}</p>
            </div>
          </div>
    
          {/* Remove Button */}
          <div className="flex justify-between items-center">
            <div className="border border-neutral-600 rounded-full px-3 py-1 flex items-center justify-center">
              <button>Remove</button>
            </div>
    
            {/* Is Active Toggle */}
            <div className="flex items-center justify-center">
              <label
                htmlFor={`${name}Toggle`}
                className="flex items-center cursor-pointer "
              >
                <div className="relative">
                  <input
                    id={`${name}Toggle`}
                    type="checkbox"
                    className="sr-only"
                    onClick={handleClick}
                  />
                  <div
                    className={`flex items-center ${
                      activeState ? "bg-red-400 " : "bg-gray-600 "
                    } w-11 h-6 rounded-full transition-all px-[2px]`}
                  >
                    <div
                      className={`bg-white w-5 h-5 rounded-full ${
                        activeState ? "translate-x-5" : "translate-x-0"
                      } transition-all`}
                    ></div>
                  </div>
                </div>
              </label>
            </div>
          </div>
        </div>
      );
    };
    
    • 2

相关问题

  • 合并排序不起作用 - Javascript代码:即使在调试后也无法找到错误

  • select.remove() 方法工作得很奇怪[关闭]

  • useOpenWeather() 中总是出现 401 res -react-open-weather lib [重复]

  • 输入元素没有只读属性,但字段仍然不可编辑[关闭]

  • 如何编辑 D3.js RadialTree 的第一个节点半径?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve