Ewerton Francis-BlogCompreendendo fragmentos do React
title-image

O que é um fragmento React?

Fragmentos são sintaxes que nos permitem adicionar vários elementos a um componente React sem envolvê-los em um nó DOM extra.

Vamos dar uma olhada no código a seguir:

const App = () => {return (<h1>This is heading1 text</h1>);}export default App

Este é um componente React simples. Quando retornamos apenas um JSX em um componente, podemos evitar envolver o JSX em outro elemento wrapper, como visto acima. No entanto, quando adicionamos mais de um elemento JSX, assim:

const App = () => {return (<h1>This is heading1 text</h1><p>This is paragraph text</p>);}export default App

Encontraremos um SyntaxError. E assim, travando nossa aplicação em desenvolvimento.

No React, quando um componente retorna vários elementos, precisamos envolvê-los em um elemento contêiner como divpara que o código funcione:

const App = () => {return (<div><h1>This is heading1 text</h1><p>This is paragraph text</p></div>);};export default App;

Embora isso seja bom, pode causar problemas indesejados em nossos componentes.

Fragmento de reação vs.div

Não há problema com divcontêineres se eles servirem a um propósito como adicionar estilos ao JSX. No entanto, eles nem sempre são necessários para encapsular nosso JSX. Neste caso, quando o fazemos, eles se tornam nós extras que desorganizam a árvore DOM.

Às vezes, quando trabalhamos com componentes aninhados, esses wrappers podem causar anomalias no código. Por exemplo, eles divpodem fazer com que o layout quebre ao trabalhar com o CSS Flexbox e Grid. Também podemos experimentar HTML inválido para elementos que devem seguir uma estrutura específica como ul > lie table>tr>td.

Dito isso, daremos uma olhada em alguns desses problemas na prática e veremos como o React Fragment os resolve. Começando com o layout CSS com Flexbox.

Usando divwrapper em um layout CSS

Considere o exemplo a seguir para criar um layout simples de linhas e colunas usando Flexbox :

import "./styles.css";const Row = ({ children }) => <div className="row">{children}</div>;const Column = ({ children }) => <div className="col">{children}</div>;const Box = ({ color }) => (<div className="box" style={{ backgroundColor: color }}></div>);export default function App() {return (<Row><Column><Box color="#007bff" /></Column><Column><Box color="#fc3" /></Column><Column><Box color="#ff3333" /></Column></Row>);}

Cada um Rowrenderiza um div, envolvendo conteúdo alinhado em uma única linha, e um Columnrenderiza envolvendo conteúdo de forma vertical. Dentro de cada Column, há um Boxcomponente que renderiza um simples divcom um contêiner de largura fixa e uma cor de fundo passada como props para ele:

/* styles.css */.row {display: flex;}.col {flex: 1;}.box {min-width: 100px;min-height: 100px;}

O código acima renderiza três colunas em uma única linha, conforme mostrado abaixo:

https://blog.logrocket.com/wp-content/uploads/2021/03/Code-render-três-color-columns.png

Veja você mesmo no CodeSandbox .

Vamos refatorar o código acima para separar as duas primeiras colunas em um componente diferente chamado ChildComponent. Imagine isso como um componente reutilizável que você pode querer desacoplar:

export default function App() {return (<Row><ChildComponent /><Column><Box color="#ff3333" /></Column></Row>);}const ChildComponent = () => (<div><Column><Box color="#007bff" /></Column><Column><Box color="#fc3" /></Column></div>);

O resultado esperado deveria ser o mesmo de antes, mas não é. Desacoplar as duas primeiras colunas em um componente separado, ChildComponent, quebra o layout:

https://blog.logrocket.com/wp-content/uploads/2021/03/Layout-break-child-component-result.png

Veja você mesmo no CodeSandbox .

O ChildCompoenttem um divencapsulando todos os seus elementos JSX para agrupá-los. No entanto, o extra divcausa uma quebra no layout porque o navegador pensa que é parte do layout.

Seu navegador não sabe que você adicionou o divpara evitar erros e ele é usado apenas como um wrapper para seu HTML envolvente.
⁠Como a árvore de componentes se aninha mais profundamente, pode ser difícil depurar e rastrear de onde os nós extras estão vindo. Da mesma forma, se estivermos usando grades CSS para estilizar e projetar nossos layouts, divs desnecessários podem fazer com que o layout quebre.

Por que usamos fragmentos no React?

Fragmentos React servem como uma alternativa mais limpa ao uso de desnecessários divsem nosso código. Esses fragmentos não produzem nenhum elemento extra no DOM, o que significa que os componentes filhos de um fragmento serão renderizados sem nenhum nó DOM de encapsulamento.

Os fragmentos do React nos permitem agrupar vários componentes irmãos sem introduzir nenhuma marcação desnecessária no HTML renderizado.

Usando fragmento no layout CSS Flexbox

Agora, voltando ao nosso código, podemos corrigir o problema de layout envolvendo o JSX do componente em um fragmento React em vez de div:

import React from 'react';const ChildComponent = () => (<React.Fragment><Column><Box color="#007bff" /></Column><Column><Box color="#fc3" /></Column></React.Fragment>);

Veja você mesmo no CodeSandbox .

Criando e renderizando fragmentos no React

Há muitas maneiras de criar e renderizar fragmentos. Você pode criar um fragmento usando a Fragmentpropriedade no objeto React importado, como mostrado acima. Você também pode importar um fragmento do React como um componente React e usá-lo de forma semelhante:

import React, {Fragment} from 'react';const ChildComponent = () => (<Fragment><Column><Box color="#007bff" /></Column><Column><Box color="#fc3" /></Column></Fragment>);

Por fim, você pode criar um fragmento React na hora usando a sintaxe abreviada para encapsular componentes usando um elemento HTML vazio como a sintaxe, <></>. Esta é a maneira mais limpa e fácil de usar fragmentos; quase parece que você está usando um elemento HTML regular:

const ChildComponent = () => (<><Column><Box color="#007bff" /></Column><Column><Box color="#fc3" /></Column></>);

Usar qualquer um dos três métodos acima traz de volta o layout original porque elimina o que não faz sentido divno DOM.

Renderizando listas em um divwrapper

Vamos dar uma olhada em outro caso de uso comum para fragmentos. Digamos que você queira renderizar uma lista de itens na página. Essa lista pode ser estática, gerada de um arquivo JSON local ou recuperada de uma API.

Para resumir, usaremos uma lista estática:>

import React from 'react';const items = ["Item 1", "Item 2", "Item 3"];const ItemRenderer = ({ item }) => (<div><p>Rendering item:</p><p>{item}</p></div>);const renderItem = () => items.map((item, index) =><ItemRenderer key={index} item={item} />);

Aqui, você está simplesmente fazendo um loop pelo array items e passando cada item como props para o ItemRenderercomponente, que renderiza cada item na página. Se você inspecionar o código acima em um navegador, você terá a seguinte estrutura DOM:

<div><p>Rendering item:</p><p>Item 1</p></div><div><p>Rendering item:</p><p>Item 2</p></div><div><p>Rendering item:</p><p>Item 3</p></div>

Cada item é renderizado em um pai divque não tem significância como um wrapper. Como não há estilo ou dados anexados ao div, ele pode ser substituído com segurança por um fragmento React.
⁠
⁠Renderizando listas com fragmentos React

Vamos substituir o divwrapper por um fragmento React assim:

import React from 'react';const items = ["Item 1", "Item 2", "Item 3"];const ItemRenderer = ({ item }) => (<><p>Rendering item:</p><p>{item}</p></>);const renderItem = () => items.map((item, index) =><ItemRenderer key={index} item={item} />);

A estrutura do DOM parece muito mais limpa agora:

<p>Item de renderização:</p><p>Item 1</p><p>Item de renderização:</p><p>Item 2</p><p>Item de renderização:</p><p>Item 3</p>

Este é um caso de uso muito simplificado, onde você pode estar renderizando um extra divno seu DOM. Quanto maiores forem suas listas, mais significativo será o impacto.

À medida que seu aplicativo se torna maior em tamanho e complexo em arquitetura, você pode acabar renderizando uma quantidade significativa de divs desnecessários para renderizar listas grandes em seu aplicativo. Isso pode inchar seu HTML, causando problemas de desempenho em dispositivos mais antigos.

Mais ótimos artigos da LogRocket:

Pode não ser tão significativo assim, mas renderizar elementos HTML desnecessários é sempre uma prática ruim. Se você tem um componente de lista genérico para seu aplicativo, considere usar fragmentos como wrappers para evitar abstrair do código limpo e da semântica.

Usando o keyprop com fragmentos React

Alguns cenários exigem o uso de keyprops em um fragmento. Vamos dar uma olhada no código a seguir:

const items = [{name: "Ibas", title: "developer"},{name: "John", title: "teacher"},];const App = () => (<><h1>List of all items:</h1>{items.map(({name, title}, index) => (<div key={index}><p>{name}</p><p>{title}</p></div>))}</>);export default App;

O foco aqui está na iteração com o map()método. Como sabemos, sempre que mapeamos itens no React para renderizar uma lista, o React usa a keyprop para identificar quais dos itens mudaram, foram removidos ou adicionados.

Além disso, sempre que mapearmos itens para renderizar vários JSX, precisamos encapsular o JSX em um elemento de contêiner.

No código acima, nós encapsulamos o JSX com a dive atribuímos a keyprop necessária. Funciona bem, mas vamos supor que o divé redundante na árvore DOM e não queremos renderizá-lo. Como você pode imaginar, precisamos substituí-lo por um fragmento.

Mas, usar a notação abreviada <></>não funcionará aqui porque ela não pode receber um atributo. Em vez disso, podemos usar a sintaxe React.Fragmentor . Esteja ciente de que essa sintaxe aceita apenas a prop por enquanto.Fragmentkey

Então, ao aplicar o keyprop no fragmento, nosso código agora se parece com isto:import React from "react";// ...const App = () => (<><h1>Lista de todos os itens:</h1>{items.map(({ name, title }, index) => (<React.Fragment key={index}><p>{name}</p><p>{title}</p></React.Fragment>))}</>);export default App;

Veja você mesmo no CodeSandbox . Não fica mais simples.

Conclusão

Fragmentos permitem que você escreva código mais limpo, legível e sustentável. Eles não são um substituto para divs no seu HTML, mas oferecem uma abordagem melhor para estruturar e renderizar sua marcação se você estiver usando divs desnecessários no seu código.

Você pode evitar problemas que quebram seus layouts ou potencialmente otimizar seu tempo de renderização de marcação usando fragmentos. No entanto, você só deve usá-los quando necessário. Se você precisar de um wrapper para seu JSX para estilização, use um divem vez disso.