Compare two arrays in react and filter one based on matches of name property

Viewed 44

I'm trying to filter a players array by comparing the names property to a roster array and rendering the matches from the players array.

When a user selects a year the getCollegeRoster() function returns players who have a year property matching the selection. From there I'm trying to filter and display the .name matches from the players array, but it seems i'm unable to update playerStateValue. I'm using recoil to manage state. Any insight would be much appreciated.

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() }));
      setRoster(collegeRoster as unknown as Roster[]);
      console.log('collegePlayers', roster);
    } catch (error: any) {
      console.log("getCollegePlayers error", error.message);
    }
    setLoading(false);
  };


const onSelection = (newSelection: any) => {
    setSelection(newSelection);
    console.log('newselect', newSelection)
    getCollegeRoster();
    const filteredArray = [...playerStateValue.players].filter((el) => ({
      name: el.name,
      match: [...roster].some((f) => f.name === el.name)
      })
    );
      setPlayerStateValue((prev) => ({
        ...prev,
        players: filteredArray as Player[],
        playersCache: {
          ...prev.playersCache,
          [communityData?.id!]: filteredArray as Player[],
        },
        playerUpdateRequired: false,
      }));
   } ```  


also tried adding setplayerstatevalue into the getcollegeroster function:


onst getCollegeRoster = async () => {
    console.log("WE ARE GETTING Players!!!");
    console.log('communitydata', communityData);

    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() }));
      setRoster(collegeRoster as unknown as Roster[]);
      console.log('collegePlayers', roster);
      const filteredArray = [...playerStateValue.players].filter((el) => ({
        name: el.name,
        match: [...roster].some((f) => f.name === el.name)
        })
      );
        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);
  };




{playerStateValue.players.map((player: Player, index) => (
            <PlayerItem
              key={player.id}
              player={player}
              // postIdx={index}
              onPlayerVote={onPlayerVote}
              userVoteValue={
                playerStateValue.playerVotes.find((item) => item.playerId === player.id)
                  ?.voteValue
              }
              onSelectPlayer={onSelectPlayer}
            />
1 Answers

I believe I found the problem. getCollegeRoster() is an async function which means it is being executed asynchronous. That function is responsible for updating roster and you are using roster inside your filtering while it is being asynchronously updated.

There is no guarantee that roster is updated by the time you filter your array.

You have two ways of solving this. Either you execute setPlayerStateValue() inside of getCollegeRoster() or you wait for getCollegeRoster() to be done by preappending it with await and your onSelection function with async:

  const onSelection = async (newSelection: any) => {
    setSelection(newSelection);
    console.log("newselect", newSelection);
    await getCollegeRoster();
    const filteredArray = [...playerStateValue.players].filter((el) => ({
      name: el.name,
      match: [...roster].some((f) => f.name === el.name),
    }));
    ...

Edit:

Another scenario I can think of is that playerStateValue might be the culprit. In React setState works asynchronous as well, if you access playerStateValue via curr/prev-callback, it is guaranteed that you are accessing the values of the current state object while updating the state. Try this use of setPlayerStateValue:

    setPlayerStateValue((prev) => {
      const filteredArray = prev.players.filter((el) => ({
        name: el.name,
        match: [...roster].some((f) => f.name === el.name),
      })) as Player[];

      return {
        ...prev,
        players: filteredArray,
        playersCache: {
          ...prev.playersCache,
          [communityData?.id!]: filteredArray,
        },
        playerUpdateRequired: false,
      };
    });
Related