2

I have an array of players which I map through. The user is constantly adding new players to this array. I map through the array and return a set of elements. I'd like each player from the list to render one at a time with a 500ms interval in between. Here's the code I have so far:

export const ShowDraftedPlayers = props => {
  const {
    draftedPlayers,
    getPlayerProfile,
    teams,
    draftPos,
    myTeam } = props;
  let playersDraftedList = draftedPlayers.map((player, index) => {
    return (
      <div key={index} className='drafted'>
        <p style={style}>TEAM {player.teamDraftedBy} </p>
          <b className='player-lastName'> {player.displayName} </b>
           {player.position}
        </p>
      </div>
    )
  })
  return (
    <div className='draftedPlayers-container'>
      {playersDraftedList}
    </div>
  )
}
3
  • 4
    Basically, what would you do is keep a state of the shown drafted players, and create an interval that adds to the state array item from the props each time. Commented Jun 10, 2020 at 16:00
  • Use animate react native Commented Jun 10, 2020 at 16:01
  • 2
    You have 2 issues here, 1: setTimeout inside a map isn't really ideal, hacks like increasing the timeout values for each item is just that, a hack. 2: React doesn't work that way, you can't pausing rendering in React, like everything else that updates in React, you need to use state. Commented Jun 10, 2020 at 16:01

2 Answers 2

6

You can use an effect to create an interval which updates a counter every 500ms; your render logic can then render a growing slice of the array each time.

export const ShowDraftedPlayers = props => {
  const {
    draftedPlayers,
    getPlayerProfile,
    teams,
    draftPos,
    myTeam
  } = props;

  const [count, setCount] = useState(0);

  useEffect(() => {
    let counter = count;
    const interval = setInterval(() => {
      if (counter >= draftedPlayers.length) {
        clearInterval(interval);
      } else {
        setCount(count => count + 1);
        counter++; // local variable that this closure will see
      }
    }, 500);
    return () => clearInterval(interval); 
  }, [draftedPlayers]);

  let playersDraftedList = draftedPlayers.slice(0, count).map((player, index) => {
    return (
      <div key={index} className='drafted'>
        <p style={style}>TEAM {player.teamDraftedBy} </p>
          <b className='player-lastName'> {player.displayName} </b>
           {player.position}
        </p>
      </div>
    )
  })
  return (
    <div className='draftedPlayers-container'>
      {playersDraftedList}
    </div>
  )
}
Sign up to request clarification or add additional context in comments.

2 Comments

Hi, very helpful your function!! I have adapted to my project and I wonder if it has a way to customize the interval time instead of fixed. I have a list of array and not all items can have the same fixed amount of interval time. Thank you
@dev.doc should be possible if you call setTimeout on with a dynamic value (derived from the counter?) instead of setInterval. If you get stuck, best to ask in a separate question.
1

You don't. setTimeout is asynchronous, as so is JavaScript and React. Components are rendered as soon as possible so that JavaScript can jump to do something else. The best way is to create a hook that reacts (pun intended) to some change in value, in this case props.draftedPlayers, setTimeout for 500ms, then add that new player to an internal players state and let the component renders based on it.

Here is how the component will reflect a change in props.draftedPlayers with a delay of 500ms:

export const ShowDraftedPlayers = props => {
  const {
    draftedPlayers,
    getPlayerProfile,
    teams,
    draftPos,
    myTeam 
  } = props;

  const [players, setPlayers] = useState([]);

  // Set internal `players` state to the updated `draftedPlayers`
  // only when `draftedPlayers` changes.
  useEffect(() => {
    const delay = setTimeout(() => {
      setPlayers(draftedPlayers);
    }, 500);
    return () => clearTimeout(delay);
  }, [draftedPlayers]);

  let playersDraftedList = players.map((player, index) => {
    return (
      <div key={index} className='drafted'>
        <p style={style}>TEAM {player.teamDraftedBy} </p>
          <b className='player-lastName'> {player.displayName} </b>
           {player.position}
        </p>
      </div>
    );
  };
};

Whenever draftedPlayers prop is changed (players added or removed) from the outer context, the component will update its players array after a delay of 500ms.

1 Comment

Consider adding clearTimeout so that you will only have one setTimeout running at once.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.