React中API数据获取与选中项同步至表格的问题排查
问题描述
我有两个表格:全部产品表与已选产品表,当前使用jsonplaceholder/users接口进行演示。全部产品表配备搜索栏,可展示API返回的所有数据。全部产品表的每条数据均带有复选框,我希望勾选复选框时,对应数据能同步显示在已选产品表中。但checked状态的useState()始终返回空数组[],无法获取选中数据,导致已选产品表无法正常展示选中项。
useState钩子及函数代码
const [checked, setChecked] = useState([]) const [input, setInput] = useState(""); const [results, setResults] = useState([]) const [apiData, setApiData] = useState([]); const handleAPI = async (url) => { try { let fetchData = await fetch("https://jsonplaceholder.typicode.com/users"); let data = await fetchData.json(); setApiData(data); const result = data.filter((user) => { return ( url && user && user.name && user.name.toLowerCase().includes(url) ) }) // console.log(result) setResults(result) } catch (err) { console.log(err) } } useEffect(() => { handleAPI() }, []) const handleSearch = (value) => { setInput(value); handleAPI(value); } const handleCheck = (id) => { setChecked(prevState => [...prevState, id]) console.log(checked) } const handleDelete = (product) => { const deleteData = checked.filter((item) => item.id !== product.id); setChecked(deleteData) }
全部产品表代码
<table className='w-full h-max'> <tr> <th className='flex items-center gap-3 text-left' > <img src={dashboardCheckbox} alt="checkbox" /> <p className='text-xs text-[#667085] font-medium'>Product</p> </th> <th className='text-left'> <p className='text-xs text-[#667085] font-medium'>Price</p> </th> <th className='text-left'> <p className='text-xs text-[#667085] font-medium'>Status</p> </th> </tr> {results.map((res, id) => ( <tr key={id} > <td className='flex items-center py-4'> <input onClick={(id) => handleCheck(res.id)} type="checkbox" className='w-[19px] h-[19px] mr-[0.8rem] cursor-pointer' /> <div className='flex items-center gap-3'> <img src={avatar} alt="" /> <div> <div className='text-sm font-medium'>{res.name}</div> <div className='text-sm text-[#667085]'>{res.company.name}</div> </div> </div> </td> <td className='text-sm'>₹160</td> <td className='text-xs'>• Not Available</td> </tr> ))} </table>
已选产品表代码
<table className='w-full h-max'> <tr className=''> <th className='flex items-center gap-3 text-left' > <p className='text-xs text-[#667085] font-medium'>Product</p> </th> <th className='text-left'> <p className='text-xs text-[#667085] font-medium'>Price</p> </th> </tr> {checked.map((r, id) => ( <tr key={id}> <td className='flex items-center py-4'> <div className='flex items-center gap-3'> <img src={avatar} alt="" /> <div> <div className='text-sm font-medium'>{r.name}</div> <div className='text-sm text-[#667085]'>seller</div> </div> </div> </td> <td className='text-sm'>₹160</td> <td className='text-sm cursor-pointer' onClick={(id) => handleDelete(id)}>Delete</td> </tr> ))} </table>
问题分析与修复方案
核心问题
checked存储id数组,但已选表直接遍历id取属性:checked里存的是用户id,不是完整对象,r.name会报错,导致渲染失败。handleCheck仅处理勾选,未支持取消:只能往数组加id,无法移除,逻辑不完整。- checkbox未绑定状态:勾选后视觉上不会保持选中,体验差。
handleDelete逻辑错误:传入的是id,但代码用item.id !== product.id判断,而item本身是id,条件永远成立,删除无效。- 初始搜索逻辑缺陷:
url为空时,过滤条件url && ...返回false,导致初始results为空数组。
修复步骤
1. 修复handleCheck,支持勾选/取消勾选
const handleCheck = (id) => { setChecked(prevState => { // 存在则移除,不存在则添加 return prevState.includes(id) ? prevState.filter(item => item !== id) : [...prevState, id]; }); }
2. 给checkbox绑定状态,替换onClick为onChange
<input type="checkbox" className='w-[19px] h-[19px] mr-[0.8rem] cursor-pointer' checked={checked.includes(res.id)} onChange={() => handleCheck(res.id)} />
3. 修复已选产品表渲染逻辑,从apiData匹配完整数据
{// 根据checked中的id筛选出完整用户数据 apiData.filter(user => checked.includes(user.id)).map((r) => ( <tr key={r.id}> {/* 用用户id作为key,更稳定 */} <td className='flex items-center py-4'> <div className='flex items-center gap-3'> <img src={avatar} alt="" /> <div> <div className='text-sm font-medium'>{r.name}</div> <div className='text-sm text-[#667085]'>{r.company.name}</div> </div> </div> </td> <td className='text-sm'>₹160</td> <td className='text-sm cursor-pointer' onClick={() => handleDelete(r.id)}>Delete</td> </tr> ))}
4. 修复handleDelete函数
const handleDelete = (id) => { setChecked(prevState => prevState.filter(item => item !== id)); }
5. 优化handleAPI搜索逻辑,支持初始加载所有数据
const handleAPI = async (url) => { try { let fetchData = await fetch("https://jsonplaceholder.typicode.com/users"); let data = await fetchData.json(); setApiData(data); const result = data.filter((user) => { // 空搜索返回所有数据,否则按名称模糊匹配(不区分大小写) if (!url) return true; return user?.name?.toLowerCase().includes(url.toLowerCase()); }); setResults(result); } catch (err) { console.log(err); } }
内容的提问来源于stack exchange,提问作者SE1822
相关产品推荐
相关产品推荐

