最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use setTimeout within a .map() in reactJS - Stack Overflow

programmeradmin7浏览0评论

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>
  )
}

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>
  )
}
Share Improve this question asked Jun 10, 2020 at 15:56 Luiz AlmeidaLuiz Almeida 811 silver badge7 bronze badges 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. – Gershon Papi Commented Jun 10, 2020 at 16:00
  • Use animate react native – Denis Tsoi 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. – Keith Commented Jun 10, 2020 at 16:01
Add a ment  | 

2 Answers 2

Reset to default 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>
  )
}

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 ponent renders based on it.

Here is how the ponent 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 ponent will update its players array after a delay of 500ms.

发布评论

评论列表(0)

  1. 暂无评论