【问题标题】:React local state does not update after onclickonclick 后反应本地状态不更新
【发布时间】:2022-02-04 00:26:06
【问题描述】:

我有一组数据。我已经映射了数据并将其传递给我的子组件。我将子组件中的项目传递给我的自定义清单。当我点击每个项目时,我可以选择和取消选择它。

我想选择所有项目。我通过向我的父组件添加一个按钮来做到这一点。当用户单击“全选”按钮时。它将获取所有数据标识符并将它们传递给本地状态。它有效,但我认为这不是最好的解决方案。因为在我的复选框中,我将所选项目的布尔值传递给复选框的组件本地状态。当我按下多合一按钮时。这个本地状态不会改变。它默认显示一个 false 值。

我在code-sandbox复制代码

这是我的父组件

import "./styles.css";
import Multipicking from "./MultiPicking";
import React, { useState } from "react";

export default function App() {
  const Data = [
    {
      id: "FF",
      level: 2,
      name: "rice"
    },
    {
      id: "AA",
      level: 2,
      name: "juice"
    },
    {
      id: "GAA",
      level: 2,
      name: "ball"
    },
    {
      id: "FF3AA",
      level: 2,
      name: "TV"
    },
    {
      id: "FH",
      level: 2,
      name: "Pencil"
    },
    {
      id: "FHAA",
      level: 2,
      name: "Tea"
    }
  ];
  const [selectedIds, setSelectedIds] = useState<string[]>([]);
  const checkAllItems = (): void => {
    const test = Data.map((item) => item.id);
    setSelectedIds(test);
  };
  return (
    <div className="App">
      <button onClick={checkAllItems}>select all</button> 
      {Data.map((item, index) => (
        <Multipicking
          selectedIds={selectedIds}
          setSelectedIds={setSelectedIds}
          key={index}
          item={item}
          index={index}
        />
      ))}
    </div>
  );
}

这是我的子组件

import React from "react";

import MultiPickingItemsCheckBox from "./MultiPickingItemsCheckBox";

interface Props {
  item?: any;
  index?: number;
  selectedIds?: string[];
  setSelectedIds?: (selectedIds: string[]) => void;
}

const MultiPickingItems: React.FC<Props> = ({
  item,
  selectedIds,
  setSelectedIds
}) => {
  return (
    <>
      <MultiPickingItemsCheckBox
        name={`${item.level} ${item.name}`}
        id={item.id}
        setSelectedIds={setSelectedIds}
        selectedIds={selectedIds}
        level={item.level}
        selected={selectedIds.includes(item.id)} // selected
      />
    </>
  );
};

export default MultiPickingItems;

这是复选框组件

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

const Label = styled.label<{
  selected: boolean;
}>`
  display: flex;
  background: ${({ selected }): string => (selected ? "lightblue" : "gray")};
  justify-content: space-between;
  align-items: center;
  width: auto;
  height: 50px;
  margin-bottom: 16px;
  border-radius: 2px;

  font-size: 16px;
  padding: 4px;

  border-left-width: 3px;
  border-left-style: solid;
`;

const Left = styled.span`
  display: flex;
  flex-direction: column;
  flex: 1;
  text-align: left;
  padding: 4px;
`;

const Name = styled.span`
  font-size: 18px;
  padding-bottom: 6px;
`;

const Check = styled.input.attrs({
  type: "checkbox"
})`
  position: absolute;
  z-index: -1;
  width: 0;
  height: 0;
  opacity: 0;
`;

const SVG = styled.svg.attrs({
  width: 30,
  height: 30,
  viewBox: "0 0 100 100"
})``;

const Circle = styled.circle.attrs({
  r: 35,
  cx: 50,
  cy: 45,
  strokeWidth: 5,
  transform: "rotate(-90, 50, 50)"
})<{ checked: boolean }>`
  fill: transparent;
  stroke-dasharray: 282.743;
  stroke-dashoffset: ${({ checked }): number => (checked ? 0 : 282.743)};
  stroke: "red";
  transition: all 0.3s linear;
`;

const Mark = styled.path.attrs({
  d: "M25 50l15 18 24 -40",
  fill: "none",
  strokeWidth: 8
})<{ checked: boolean }>`
  transition: all 0.3s linear;
  stroke-dashoffset: ${({ checked }): number => (checked ? 0 : 100)};
  stroke-dasharray: 100;
  stroke: "red";
`;

interface Props {
  name?: string;
  selectedIds?: string[];
  setSelectedIds?: (selectedItemsId: string[]) => void;
  disabled?: boolean;
  id?: string;
  isDragging?: boolean;
  level?: number;
  selected?: boolean;
}

const MultiPickingItemsCheckBox: React.FC<Props> = ({
  name,
  selectedIds,
  setSelectedIds,
  id,
  disabled,

  level,
  selected
}) => {
  const [checked, setChecked] = useState(selected);

  const handleChange = (): void => {
    setChecked(!checked);
    if (checked) {
      setSelectedIds(selectedIds.filter((selectedId) => selectedId !== id));
    } else {
      setSelectedIds([...selectedIds, id]);
    }
  };

  console.log({ checked });

  return (
    <Label level={level} disabled={disabled} selected={selected}>
      <Left>
        <Name>{name}</Name>
      </Left>
      <Check
        id={`field-${id}`}
        name={name}
        checked={checked}
        onChange={handleChange}
        disabled={disabled}
      />
      <SVG>
        <Circle checked={checked} />
        <Mark checked={checked} />
      </SVG>
    </Label>
  );
};
export default MultiPickingItemsCheckBox;

【问题讨论】:

    标签: reactjs checkbox state


    【解决方案1】:

    你需要有一个单一的事实来源,应该是 selectedIds。

    • 在checkbox组件中去掉本地状态,直接使用selected
    • 提示:在复选框组件中,您还可以删除 selectedIds 道具并在 handleChange 函数中使用 mutator 函数:
    const handleChange = (): void => {
        if (selected) {
          setSelectedIds(selectedIds => selectedIds.filter((selectedId) => selectedId !== id));
        } else {
          setSelectedIds(selectedIds => ([...selectedIds, id]));
        }
    };
    

    沙盒:https://codesandbox.io/s/cranky-currying-thu5s

    【讨论】:

    • 所以,使用另一种状态是错误的。
    • 我可以问你一个问题,当我选择了所有项目时。我将它传递给const [checked, setChecked] = useState(selected);。在控制台中选择为真但检查为假,你能解释一下为什么
    • 因为给useState提供的参数只是用来初始化你的状态值,所以即使你改变它的值也不会再次被使用。
    • 所以当你启动你的应用程序时,没有选择任何东西,selected 是假的,所以checked 被初始化为值false。然后你检查所有项目,selected 变为 true 但检查没有改变。
    • 检查不更新的任何原因。如果我使用useCallback 会发生什么
    猜你喜欢
    • 2020-04-19
    • 1970-01-01
    • 2021-02-18
    • 2022-11-17
    • 2020-09-29
    • 1970-01-01
    • 2021-03-31
    • 2018-03-28
    相关资源
    最近更新 更多