如何对比两个API返回的ID数组,过滤重复ID并更新options状态?
问题:过滤API返回的重复ID并生成指定格式的选项数组
我通过两次不同的API调用得到两个ID数组,想要过滤掉已存在于第一个数组(prevAdmins)中的ID,把剩余ID以{value: ID, label: 名称}的格式存入options状态,但现有代码没实现这个需求,求帮忙。
现有代码
const [prevAdmins, setPrevAdmins] = useState<any>([]); const [options, setOptions] = useState([{value: "", label: ""}]); // API 1 CALL get_user_groups({bot_id: params.botid, group_id: params.userid}).then((res) => { setDetails(res?.data?.data[0]); setGroupName(res?.data?.data[0].name) let prevAdmins: any = []; res?.data?.data[0]?.join_details.map((prevJoinee, idx) => { prevAdmins.push(prevJoinee.user_id) setPrevAdmins(prevAdmins) }) }); // API 1 返回结果:prevAdmins = ['61dfcfb71f492f4f4f589e93', '61dedd23bd15322626dd7539'] // 2nd API CALL : get_followers({bot_id: params.botid}).then((res) => { if(res.data.data){ let option: any = []; let allAdmins: any = []; res.data.data.map((admin, index) => { allAdmins.push(admin._id); if(!prevAdmins.includes(allAdmins)){ option.push({value: admin._id, label: admin.displayName}) } }) setOptions(option); } }) // API 2 返回结果:['61dfd02a1f492f4f4f589f00', '61dfcfb71f492f4f4f589e93', '61dedd23bd15322626dd7539']
问题分析
现有代码存在几个关键问题:
- API异步顺序问题:两个API并行调用,可能第二个API先返回,此时
prevAdmins还是初始空数组,过滤逻辑完全失效。 - 状态更新错误:第一个API在
map循环中多次调用setPrevAdmins,应该在循环结束后一次性更新状态;且内部变量prevAdmins和状态变量重名,易造成混淆。 - 过滤逻辑错误:第二个API中用
!prevAdmins.includes(allAdmins),但allAdmins是数组,而prevAdmins存储的是单个ID值,应该判断当前admin._id是否不在prevAdmins数组中。
修正后的代码方案
方案1:确保API调用顺序(先执行第一个API,再调用第二个)
const [prevAdmins, setPrevAdmins] = useState<any>([]); const [options, setOptions] = useState([{value: "", label: ""}]); // 合并API调用,保证顺序 const fetchData = async () => { // 先调用第一个API获取prevAdmins const groupRes = await get_user_groups({bot_id: params.botid, group_id: params.userid}); if (groupRes?.data?.data[0]) { setDetails(groupRes.data.data[0]); setGroupName(groupRes.data.data[0].name); // 提取所有需要排除的ID const adminIds = groupRes.data.data[0].join_details.map(item => item.user_id); setPrevAdmins(adminIds); // 调用第二个API并过滤 const followerRes = await get_followers({bot_id: params.botid}); if (followerRes.data.data) { // 转成Set提升查找效率 const excludeIds = new Set(adminIds); const filteredOptions = followerRes.data.data .filter(admin => !excludeIds.has(admin._id)) .map(admin => ({value: admin._id, label: admin.displayName})); setOptions(filteredOptions); } } }; // 组件挂载时执行 useEffect(() => { fetchData(); }, [params.botid, params.userid]);
方案2:用useEffect监听prevAdmins变化,触发第二个API
如果两个API不需要严格顺序,或者第一个API可能多次更新,可使用这种方式:
const [prevAdmins, setPrevAdmins] = useState<any>([]); const [options, setOptions] = useState([{value: "", label: ""}]); // 第一个API调用 useEffect(() => { get_user_groups({bot_id: params.botid, group_id: params.userid}).then((res) => { if (res?.data?.data[0]) { setDetails(res.data.data[0]); setGroupName(res.data.data[0].name); const adminIds = res.data.data[0].join_details.map(item => item.user_id); setPrevAdmins(adminIds); } }); }, [params.botid, params.userid]); // 监听prevAdmins变化,调用第二个API并过滤 useEffect(() => { // 只有当prevAdmins有值时才调用第二个API if (prevAdmins.length === 0) return; get_followers({bot_id: params.botid}).then((res) => { if (res.data.data) { const excludeIds = new Set(prevAdmins); const filteredOptions = res.data.data .filter(admin => !excludeIds.has(admin._id)) .map(admin => ({value: admin._id, label: admin.displayName})); setOptions(filteredOptions); } }); }, [prevAdmins, params.botid]);
说明
- 用
Set存储需要排除的ID,has方法的查找效率比数组includes更高,数据量大时优势明显。 - 统一处理API异步逻辑,避免因顺序问题导致的过滤失效。
- 去掉循环中多次更新状态的错误写法,改为一次性更新。
内容的提问来源于stack exchange,提问作者ksd030687d
相关产品推荐
相关产品推荐

