Multiple confetti effects with react-confetti on the same page

560 Views Asked by At

I want to display multiple confetti effects with the react-confetti library on the same page.

However, every time I try to do that in my component, it only appears to show the confetti effect on the last element, but not on all of them. The canvas for the confetti is correctly set to all elements (which i checked with a background-color)

confetti effect

So basically my logic is as follows:

In my ParentComponent I iterate over my players and create cards for each player. The card size/dimensions are calculated like this:

const updateCardDimensions = () => {
    if (cardRef.current) {
      const rect = cardRef.current.getBoundingClientRect();
      setCardDimensions({ width: rect.width, height: rect.height });
    }
  };

  useEffect(() => {
    // Initial update
    updateCardDimensions();

    // Attach the resize event listener
    window.addEventListener('resize', updateCardDimensions);

    // Clean up the event listener
    return () => {
      window.removeEventListener('resize', updateCardDimensions);
    };
  }, [cardRef]);

Here I iterate over my players and create cards for each player.

{gameData.players.map((player) => {
              return (
                <PlayerCardWithConfetti
                  key={player.id}
                  player={player}
                  cardDimensions={cardDimensions}
                  winners={winners}
                  cardRef={cardRef}
                  .. (removed props that are not needed for the example)
                />
              );
            })}

Then in my PlayerCardWithConfetti - Component I use the react-confetti library to create a confetti effect for my winning cards. I also set a backgroundColor to determine if my canvases for the react-confetti effect are set in the right way (which they are).

<div key={player.id} className="col-md-4 mb-3">
      <div style={{ position: 'relative' }}>
        {isPlayerWinner(player.id) && (
          <Confetti
            style={{backgroundColor: 'blanchedalmond'}}
            width={cardDimensions.width}
            height={cardDimensions.height}
            recycle={true}
            key={`confetti-${player.id}`}
          />
        )}
        <PlayerCard
          player={player}
          isWinner={winners.some((winner) => winner.id === player.id)}
          cardRef={cardRef}
          .. (removed props that are not needed for the example)
        />
      </div>
    </div>

So my expectation was that this would show me a confetti effect for each card that meets the conditions and the canvas is actually set right for each card so that works. But sadly the confetti effect is only present in the last card:

confetti effect

I then thought the loop might cause the issues so I recreated the cards manually but it still only shows the confetti effect in the last card:

 <PlayerCardWithConfetti
              key={Math.random()}
              player={gameData.players[0]}
              cardDimensions={cardDimensions}
              winners={winners}
              cardRef={cardRef}
              .. (removed props that are not needed for the example)
            />
            <PlayerCardWithConfetti
              key={Math.random()}
              player={gameData.players[1]}
              cardDimensions={cardDimensions}
              winners={winners}
              cardRef={cardRef}
              .. (removed props that are not needed for the example)
            />

I then tried to use two effects of the react-confetti that are not related to my components in any way and created a small example that would display one effect absolute in the bottom left corner and one absolute in the bottom right corner, which worked without problem. So I'm assuming it may has to do with some react rendering or something like that?

I'd be so happy for anyone that knows that library/react and would be able to help me with that problem since I'm trying to solve this since two days.

Thank you all!

1

There are 1 best solutions below

0
ffilasta On

I solve this kind of problem by passing canvas ref to the Confetti component. Something like this :

export function MyConfetti(){
   const confettiRef = useRef<HTMLCanvasElement>(null)
   return (<Confetti ref={confettiRef}/>)
}