React中布尔数组状态初始化为空数组,求原因及解决方案
问题分析与解决方案
你的核心问题是**checkedItems状态初始化后始终为空数组**,原因在于:
- 组件首次渲染时,
productList的初始值是空数组[],所以new Array(productList.length).fill(false)生成的是空数组,而useState的初始值只会在组件首次挂载时生效,后续productList通过API获取到数据后,不会自动重新初始化checkedItems。 - 另外你当前的
handleOnChange里的reduce逻辑存在错误,无法正确收集选中的SKU列表。
修复步骤
1. 同步checkedItems与productList的长度
添加一个useEffect监听productList的变化,当产品列表加载完成后,初始化checkedItems为对应长度的false数组:
useEffect(() => { // 当productList有数据时,初始化checkedItems为对应长度的false数组 if (productList.length > 0) { setCheckedItems(new Array(productList.length).fill(false)); } }, [productList]);
2. 修正checkedItems的初始化方式
直接初始化为空数组即可,后续通过上面的useEffect同步:
const [checkedItems, setCheckedItems] = useState<boolean[]>([]);
3. 修复选中SKU的收集逻辑
原来的reduce函数缺少初始值,且逻辑错误,无法正确收集所有选中的SKU。修改handleOnChange中的skuList生成逻辑:
const handleOnChange = (position: number) => { const updatedCheckedItems = checkedItems.map((item, index) => index === position ? !item : item ); setCheckedItems(updatedCheckedItems); // 收集所有选中的产品SKU const skuList = productList.filter((_, index) => updatedCheckedItems[index]) .map(item => item.sku); setDeleteList(skuList); };
4. 可选:优化复选框的checked属性判断
避免checkedItems[index]出现undefined的情况,可以添加默认值:
checked={checkedItems[index] ?? false}
完整修复后的代码
import React, { useState, useEffect } from "react"; import { Container, ItemDescription, ProductContainer } from "./style"; const API = "http://localhost:4000/select"; interface DATA { sku: string; name: string; price: string; type: string; size?: number; // 可选字段,避免类型报错 weight?: number; height?: number; width?: number; length?: number; } interface IProps { del: boolean; } const ProductDisplay = ({ del }: IProps) => { const [productList, setProductList] = useState<Array<DATA>>([]); const [checkedItems, setCheckedItems] = useState<boolean[]>([]); const [deleteList, setDeleteList] = useState<string[]>([]); // 改为string数组存储SKU useEffect(() => { const fetchData = async () => { try { const response = await fetch(API); const results = await response.json(); setProductList(results); } catch (e) { console.log(e); } }; fetchData(); }, []); // 当产品列表更新时,同步更新checkedItems的长度 useEffect(() => { if (productList.length > 0) { setCheckedItems(new Array(productList.length).fill(false)); } }, [productList]); const handleOnChange = (position: number) => { const updatedCheckedItems = checkedItems.map((item, index) => index === position ? !item : item ); setCheckedItems(updatedCheckedItems); // 收集所有选中的SKU const selectedSkus = productList .filter((_, idx) => updatedCheckedItems[idx]) .map(product => product.sku); setDeleteList(selectedSkus); }; return ( <div> {productList.length === 0 && <h4>Fetching Checkboxes ...</h4>} {productList.length > 0 && ( <Container> {productList.map((item, index) => ( <ProductContainer key={item.sku}> {/* 添加唯一key */} <input type="checkbox" value={item.sku} id={`custom-checkbox-${index}`} checked={checkedItems[index] ?? false} onChange={() => handleOnChange(index)} /> <ItemDescription> <span className="sku">{item.sku}</span> <span className="name">{item.name}</span> <span className="price">{item.price} $</span> {item.size && <span className="size">Size: {item.size}MB</span>} {item.weight && <span className="weight">Weight: {item.weight}KG</span>} {item.height && ( <span className="dimention"> Dimention: {item.height} x {item.width} x {item.length} </span> )} </ItemDescription> </ProductContainer> ))} </Container> )} </div> ); }; export default ProductDisplay;
额外说明
- 给
DATA接口的可选字段添加?,避免类型报错; - 给列表项添加
key属性(用item.sku,保证唯一性),符合React列表渲染规范; deleteList改为string[]类型,因为只需要存储SKU字符串;setCheckedItems是异步操作,所以在handleOnChange中直接打印checkedItems会显示更新前的状态,如果需要查看更新后的状态,可以添加一个监听checkedItems的useEffect。
内容的提问来源于stack exchange,提问作者Leon Murelli SIlveira
相关产品推荐
相关产品推荐

