onclick 后 React 本地状态不更新

React local state does not update after onclick

我有一个数据集。我已经映射数据并将其传递给我的子组件。我将项目从我的子组件传递到我的自定义清单。当我点击每个项目时,我可以 select 和 deselect 它。

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

我在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;

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

  • checkbox组件中去掉local state直接使用selected
  • 提示:在复选框组件中,您还可以删除 selectedIds 属性并在 handleChange 函数中使用一个修改器函数:
const handleChange = (): void => {
    if (selected) {
      setSelectedIds(selectedIds => selectedIds.filter((selectedId) => selectedId !== id));
    } else {
      setSelectedIds(selectedIds => ([...selectedIds, id]));
    }
};

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