我在做这个练习:https://www.reacterry.com/portal/challenges/select-all-checkboxes

如果您查看了check OnChange函数,我try 了多种不同的方法,但它们似乎都不起作用,我想真正了解其中的原因.

我只是对setCheckbox这一部分感到困惑.

他们的:

setCheckboxes(
    checkboxes.map((checkbox) =>
      checkbox.id === id
        ? { ...checkbox, checked: !checkbox.checked }
        : checkbox
    )
  );

我的:


//WHY DOESNT THIS WORK?
    const arr = checkboxes;
    const index = arr.findIndex((x) => x.id === id);
    console.log(index);
    console.log(arr);
    arr[index].checked = !arr[index].checked;
    setCheckboxes(arr);
    console.log(checkboxes);

    //WHY DOESNT THIS WORK?
    setCheckboxes((prevState) => {
      const arr = prevState;
      const index = arr.findIndex((x) => x.id === id);
      console.log(index);
      console.log(arr);
      arr[index].checked = !arr[index].checked;
      return arr;
    });


    //WHY DOESNT THIS WORK?
    setCheckboxes(
      checkboxes.forEach((checkbox) => {
        if (checkbox.id === id) {
          checkbox = { ...checkbox, checked: !checkbox.checked }
        }
      })
    );`

我不完全理解我的方式和这种方式之间的区别的解决方案是:

import React, { useState } from 'react';
import styled from 'styled-components';

const CheckboxList = () => {
const [checkboxes, setCheckboxes] = useState([
  { id: 1, label: 'Dogs', checked: false },
  { id: 2, label: 'Cats', checked: false },
  { id: 3, label: 'Cows', checked: false },
  { id: 4, label: 'Deers', checked: false },
]);

const handleCheckboxChange = (id) => {
  setCheckboxes(
    checkboxes.map((checkbox) =>
      checkbox.id === id
        ? { ...checkbox, checked: !checkbox.checked }
        : checkbox
    )
  );
};

const handleSelectAll = () => {
  setCheckboxes(checkboxes.map((checkbox) => ({ ...checkbox, checked: true })));
};

return (
  <Container>
    <CheckboxContainer data-testid="checkbox-container">
      {checkboxes.map((checkbox, index) => (
        <CheckboxLabel key={checkbox.id}>
          <input
            data-testid={`checkbox-${index + 1}`}
            type="checkbox"
            checked={checkbox.checked}
            onChange={() => handleCheckboxChange(checkbox.id)}
          />
          {checkbox.label}
        </CheckboxLabel>
      ))}
    </CheckboxContainer>
    <SelectAllButton data-testid="button" onClick={handleSelectAll}>Select All</SelectAllButton>
  </Container>
);
};

export default CheckboxList;

const Container = styled.div`
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin: 24px;
`;

const CheckboxContainer = styled.div`
  display: flex;
  flex-direction: column;
  gap: 5px;
`;

const CheckboxLabel = styled.label`
  display: flex;
  align-items: center;
  gap: 5px;
`;

const SelectAllButton = styled.button`
  padding: 10px 20px;
  font-size: 18px;
  border: none;
  border-radius: 4px;
  background-color: #333;
  color: #fff;
  cursor: pointer;
  margin-top: 24px;

  &:hover {
    opacity: 0.8;
  }
`;

我的代码如下:

import React, { useState, useEffect } from 'react';
import styled from 'styled-components';

const CheckboxList = () => {
  const [checkboxes, setCheckboxes] = useState([
    { id: 1, label: 'Dogs', checked: false },
    { id: 2, label: 'Cats', checked: false },
    { id: 3, label: 'Cows', checked: false },
    { id: 4, label: 'Deers', checked: false },
  ]);

  const checkedOnChange = (id) => {

    //WHY DOESNT THIS WORK?
    const arr = checkboxes;
    const index = arr.findIndex((x) => x.id === id);
    console.log(index);
    console.log(arr);
    arr[index].checked = !arr[index].checked;
    setCheckboxes(arr);
    console.log(checkboxes);

    //WHY DOESNT THIS WORK?
    setCheckboxes((prevState) => {
      const arr = prevState;
      const index = arr.findIndex((x) => x.id === id);
      console.log(index);
      console.log(arr);
      arr[index].checked = !arr[index].checked;
      return arr;
    });


    //WHY DOESNT THIS WORK?
    setCheckboxes(
      checkboxes.forEach((checkbox) => {
        if (checkbox.id === id) {
          checkbox = { ...checkbox, checked: !checkbox.checked }
        }
      })
    );
  };

  return (
    <Container>
      <CheckboxContainer data-testid="checkbox-container">
        {checkboxes.map((checkbox, index) => (
          <CheckboxLabel key={checkbox.id}>
            <input
              data-testid={`checkbox-${index + 1}`}
              type="checkbox"
              checked={checkbox.checked}
              onClick={() => {
                checkedOnChange(checkbox.id);
              }}
            />
            {checkbox.label}
          </CheckboxLabel>
        ))}
      </CheckboxContainer>
      <SelectAllButton data-testid="button">Select All</SelectAllButton>
    </Container>
  );
};

export default CheckboxList;

const Container = styled.div`
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin: 24px;
`;

const CheckboxContainer = styled.div`
  display: flex;
  flex-direction: column;
  gap: 5px;
`;

const CheckboxLabel = styled.label`
  display: flex;
  align-items: center;
  gap: 5px;
`;

const SelectAllButton = styled.button`
  padding: 10px 20px;
  font-size: 18px;
  border: none;
  border-radius: 4px;
  background-color: #333;
  color: #fff;
  cursor: pointer;
  margin-top: 24px;

  &:hover {
    opacity: 0.8;
  }
`;

我试了3种不同的方法,但我不确定为什么不起作用.我想充分了解其中的原因.看到一个用尽可能简单的代码编写的解决方案,这样我就可以引用它了.当我说简单时,我的意思是最好没有花哨的语法或扩散运算符.只是想出个pip .谢谢你们.

推荐答案

在您的版本中:

setCheckboxes((prevState) => {
  const arr = prevState;
  const index = arr.findIndex((x) => x.id === id);
  console.log(index);
  console.log(arr);
  arr[index].checked = !arr[index].checked;
  return arr;
});

返回的arr是与prevState相同的数组实例.该数组中的数据是mutated(在REACTIVE状态下不应该这样做),and该数组本身是相同的引用(这意味着REPACT不会see该状态已经改变).

在您的所有版本中基本上都是如此.向下钻取数组并修改其内容,然后返回相同的array.

将这一点与他们的版本进行对比:

setCheckboxes(
  checkboxes.map((checkbox) =>
    checkbox.id === id
      ? { ...checkbox, checked: !checkbox.checked }
      : checkbox
  )
);

这里要注意的第一件事是,返回值.map()被设置为新状态,而.map()创建了一个newarray.因此,Reaction将观察到数组引用不同,并且状态已更新.

需要注意的第二件事是,该数组由两个部分组成:

  1. 对于任何不符合条件的元素,使用相同的元素(对象引用)
  2. 对于does符合条件的任何元素,创建并返回new对象实例(而不是变异现有实例),该实例填充有现有实例的所有属性(扩散操作符)和一个新的(或替换的)属性

因此,总的来说,这里的要点是,当更新状态时,您应该始终为需要修改的任何对象或数组创建新的实例,而不是修改当前的实例(S).

Javascript相关问答推荐

Vue.js使用特定索引值的数据更新html

ChartJS:分组堆叠条形图渲染错误

使用JavaScript/PHP将二维码保存为服务器端的图像

Python类实现的JavaScript吊坠是什么样子的?

react 页面更改类别时如何返回第0页

创建私有JS出口

如何通过在提交时工作的函数显示dom元素?

为什么从liveWire info js代码传递数组我出现错误?

从实时数据库(Firebase)上的子类别读取数据

为什么我的includes声明需要整个字符串?

无法检测卡片重叠状态的问题

IF语句的计算结果与实际情况相反

在浏览器中触发插入事件时检索编码值的能力

当输入字段无效时,我的应用程序不会返回错误

如何利用CSS中的隐藏元素实现平滑扩展和防止网格行间隙

在表单集中保存更改时删除';禁用';

在Vercel中部署Next.js项目时获取`ReferenceError:未定义文档`

为列表中的项目设置动画

使用Reaction窗体挂钩注册日历组件

使用可配置项目创建网格