React中基于name属性过滤数组,Recoil状态更新失败求助
问题修复方案
核心问题分析
- React状态更新异步性:调用
setRoster后,roster变量不会立刻更新,直接后续使用会拿到旧值。 - filter函数逻辑错误:
filter需要返回布尔值来决定是否保留元素,但你返回的是包含match属性的对象,所有元素都会被判定为true保留,达不到过滤效果。 - 异步函数执行顺序问题:第一种写法中
onSelection里调用getCollegeRoster后立刻执行过滤,此时Firestore请求还没完成,roster还是旧数据。
修复后的代码实现
方案一:直接使用Firestore返回的数据过滤(推荐)
跳过React状态更新的异步等待,直接用请求到的原始数据处理过滤,避免状态不同步问题:
const getCollegeRoster = async () => { setLoading(true); try { const playersQuery = query( collection(firestore, `colleges/${communityData.id}/rosters`), where("year", "==", selection), ); const playerDocs = await getDocs(playersQuery); const collegeRoster = playerDocs.docs.map((doc) => ({ id: doc.id, ...doc.data() })) as Roster[]; // 直接用collegeRoster做过滤,不用等setRoster更新 const filteredArray = playerStateValue.players.filter(el => collegeRoster.some(f => f.name === el.name) ); setRoster(collegeRoster); setPlayerStateValue((prev) => ({ ...prev, players: filteredArray as Player[], playersCache: { ...prev.playersCache, [communityData?.id!]: filteredArray as Player[], }, playerUpdateRequired: false, })); } catch (error: any) { console.log("getCollegePlayers error", error.message); } setLoading(false); }; const onSelection = (newSelection: any) => { setSelection(newSelection); getCollegeRoster(); };
方案二:监听roster状态变化触发更新
如果需要保留roster状态的使用,用useEffect监听roster的变化,再更新Recoil状态:
const getCollegeRoster = async () => { setLoading(true); try { const playersQuery = query( collection(firestore, `colleges/${communityData.id}/rosters`), where("year", "==", selection), ); const playerDocs = await getDocs(playersQuery); const collegeRoster = playerDocs.docs.map((doc) => ({ id: doc.id, ...doc.data() })) as Roster[]; setRoster(collegeRoster); } catch (error: any) { console.log("getCollegePlayers error", error.message); } setLoading(false); }; const onSelection = (newSelection: any) => { setSelection(newSelection); getCollegeRoster(); }; // 监听roster变化,自动更新Recoil状态 useEffect(() => { if (roster.length === 0) return; const filteredArray = playerStateValue.players.filter(el => roster.some(f => f.name === el.name) ); setPlayerStateValue((prev) => ({ ...prev, players: filteredArray as Player[], playersCache: { ...prev.playersCache, [communityData?.id!]: filteredArray as Player[], }, playerUpdateRequired: false, })); }, [roster, playerStateValue.players, communityData?.id]);
关键修复点说明
- 修正
filter逻辑:直接返回collegeRoster.some(...)的布尔值,符合filter函数的判断要求。 - 绕过异步状态限制:直接使用Firestore返回的
collegeRoster,避免等待React状态更新的延迟。 - 确保执行顺序:过滤操作要么紧跟在数据获取完成后,要么通过状态监听触发,保证用的是最新数据。
内容的提问来源于stack exchange,提问作者Robinhood15
相关产品推荐
相关产品推荐

