Como o useGridLayout já calcula cols, qualquer um funciona. Mas CSS Grid é mais natural:
Com flexbox você teria que calcular larguras manualmente com flex-basis. Grid faz isso nativamente.
Se os players são iframes (embeds de Twitch/YouTube/etc.), um re-render do componente recarrega o iframe inteiro — o stream reinicia. Para evitar isso, 3 técnicas combinadas:
Usar o ID único do stream como key, nunca o index do array:
Evita re-render quando o pai re-renderiza mas as props do player não mudaram:
order (opcional, mais avançado)Em vez de mudar a ordem no array (o que muda a posição no DOM), manter a ordem fixa no array e usar style={{ order: posição }} para reposicionar visualmente. Assim o React não toca no DOM ao reordenar — só muda um atributo CSS.
Resumo: CSS Grid para layout + keys por ID + memo no Player. Com isso, adicionar/remover um stream só monta/desmonta aquele player específico, os outros ficam intocados.
<div style={{ display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)` }}>// ERRADO - reordear causa unmount/remount de todos
{streams.map((s, i) => <Player key={i} />)}
// CERTO - React sabe que é o mesmo elemento, só move no DOM
{streams.map(s => <Player key={s.id} />)}const Player = memo(({ streamId, width, height }) => {
return <iframe ... />
}){streams.map(s => (
<Player key={s.id} style={{ order: s.position }} />
))}