jeudi 3 février 2022

React local state does not update after onclick

I have a collection of data. I've mapped the data and passed it to my child component. I pass the items from my child component to my custom checklist. When I click each item, I can select and deselect it.

I'd like to select all of the items. I did this by adding one button to my parent component. When the user clicks the "Select All" button. It will take all data identifiers and pass them to the local state. It works, but I don't think it's the best solution. Because In my checkbox, I'm passing the boolean value of the selected item to the checkbox's component local state. When I press the all-in-one button. This local state does not change. It displays a false value by default.

I reproduce code in code-sandbox

This is my parent component

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>
  );
}

This is my child component

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;

This is the checkbox component

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;



Aucun commentaire:

Enregistrer un commentaire