Search code examples
reactjsarraysuse-effect

Array populating in UseEffect not showing up properly in React


In my useEffect I am populating two array each array there are two element. However, only one element in each array is showing on my page.

enter image description here

Here is the useEffect

  useEffect(() => {
    let tempArray = [...players];
    if (secondTeam.length < Math.floor(Number(playersCount) / 2)) {
      if (random) {
        for (let i = 0; i < 4; i++) {
          const num = Math.floor(Math.random() * tempArray.length);
          if (i < Math.floor(Number(playersCount) / 2)) {
            const tempFirstTeam = [...firstTeam];
            tempFirstTeam.push(tempArray[num]);
            setFirstTeam(tempFirstTeam);
          } else {
            const tempSecondTeam = [...secondTeam];
            tempSecondTeam.push(tempArray[num]);
            setSecondTeam(tempSecondTeam);
          }
          tempArray.splice(num, 1);
        }
      }
    }
  }, []);

Here is the entire jsx file

import { useState, useEffect } from "react";
import { registerGame } from "../features/game/gameSlice";
import { useSelector, useDispatch } from "react-redux";
import InputGroup from "react-bootstrap/InputGroup";
import { toast } from "react-toastify";
import PlayerImageAndName from "./PlayerImageAndName";

const vsStyle = {
  position: "absolute",
  top: "15%",
  left: "50%",
  transform: "translate(-50%, -50%)",
};
function PlayerSelection() {
  const { playersCount, points, random, teamOne, teamTwo } = useSelector(
    (state) => state.game.playerData
  );

  const dispatch = useDispatch();

  const { players } = useSelector((state) => state.player);
  const [firstTeam, setFirstTeam] = useState([]);
  const [secondTeam, setSecondTeam] = useState([]);
  const [playersChosen, setPlayersChosen] = useState(0);

  useEffect(() => {
    let tempArray = [...players];
    if (secondTeam.length < Math.floor(Number(playersCount) / 2)) {
      if (random) {
        for (let i = 0; i < 4; i++) {
          const num = Math.floor(Math.random() * tempArray.length);
          if (i < Math.floor(Number(playersCount) / 2)) {
            const tempFirstTeam = [...firstTeam];
            tempFirstTeam.push(tempArray[num]);
            setFirstTeam(tempFirstTeam);
          } else {
            const tempSecondTeam = [...secondTeam];
            tempSecondTeam.push(tempArray[num]);
            setSecondTeam(tempSecondTeam);
          }
          tempArray.splice(num, 1);
        }
      }
    }
  }, []);


  return (
    <div>
      <div className="d-flex" style={{ height: "350px" }}>
        <div className="p-2 flex-grow-1" style={{ display: "flex" }}>
          {firstTeam.map((player) => (
            <PlayerImageAndName key={player._id} player={player} />
          ))}
        </div>
        {secondTeam.length > 0 && (
          <div className="p-2" style={vsStyle}>
            <h1>Vs.</h1>
          </div>
        )}


  <div className="p-2 flex-grow-1" style={{ display: "flex" }}>
          {secondTeam.map((player) => (
            <PlayerImageAndName key={player._id} player={player} />
          ))}
        </div>
    </div>
  );
}
export default PlayerSelection;

Solution

  • setFirstTeam does not update firstTeam instantly

    The same is true for setSecondTeam as well. Let's take just the for loop and simplify it to make the problem more apparent:

    for (let i = 0; i < 4; i++) {
          const tempFirstTeam = [...firstTeam];
          tempFirstTeam.push(tempArray[num]);
          setFirstTeam(tempFirstTeam);
    }
    

    This loop will run 4 times and each time it happens firstTeam has not changed and will always be []. Therefore, tempFirstTeam starts as an empty array and then has 1 thing pushed in to it.

    So, instead, you need move both tempFirstTeam and tempSecondTeam outside your for loop, and set them once:

    const tempFirstTeam = [...firstTeam];
    const tempSecondTeam = [...secondTeam];
    
    for (let i = 0; i < 4; i++) {
        const num = Math.floor(Math.random() * tempArray.length);
        if (i < Math.floor(Number(playersCount) / 2)) {
           tempFirstTeam.push(tempArray[num]);
        } else {
           tempSecondTeam.push(tempArray[num]);
        }
        tempArray.splice(num, 1);
    }
    
    setFirstTeam(tempFirstTeam); 
    setSecondTeam(tempSecondTeam);