onclick 后 React 本地状态不更新
React local state does not update after onclick
我有一个数据集。我已经映射数据并将其传递给我的子组件。我将项目从我的子组件传递到我的自定义清单。当我点击每个项目时,我可以 select 和 deselect 它。
我想要 select 所有项目。我通过向我的父组件添加一个按钮来做到这一点。当用户单击“Select 全部”按钮时。它将获取所有数据标识符并将它们传递给本地状态。它有效,但我认为这不是最好的解决方案。因为在我的复选框中,我将 selected 项的布尔值传递给复选框的组件本地状态。当我按下一体机按钮时。这个本地状态不会改变。默认显示假值。
中重现了代码
这是我的父组件
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]));
}
};
我有一个数据集。我已经映射数据并将其传递给我的子组件。我将项目从我的子组件传递到我的自定义清单。当我点击每个项目时,我可以 select 和 deselect 它。
我想要 select 所有项目。我通过向我的父组件添加一个按钮来做到这一点。当用户单击“Select 全部”按钮时。它将获取所有数据标识符并将它们传递给本地状态。它有效,但我认为这不是最好的解决方案。因为在我的复选框中,我将 selected 项的布尔值传递给复选框的组件本地状态。当我按下一体机按钮时。这个本地状态不会改变。默认显示假值。
中重现了代码这是我的父组件
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]));
}
};