¿Cómo renderizo elementos hermanos sin envolverlos en una etiqueta principal?

82

En la mayoría de los casos, tener una etiqueta principal no es un problema.

React.createClass({
    render: function() {
        return (
            <tbody>
                <tr><td>Item 1</td></tr>
                <tr><td>Item 2</td></tr>
            </tbody>
        );
    }
});

Pero hay algunos casos en los que tiene sentido tener elementos hermanos en una función de renderizado sin un padre, y especialmente en el caso de una tabla, no desea envolver una fila de tabla en un archivo div.

React.createClass({
    render: function() {
        return (
            <tr><td>Item 1</td></tr>
            <tr><td>Item 2</td></tr>
        );
    }
});

El segundo ejemplo da el error siguiente: Adjacent XJS elements must be wrapped in an enclosing tag while parsing file.

¿Cómo puedo renderizar dos elementos hermanos sin envolverlos en uno <div>o algo similar?

thealexbaron
fuente
3
Siempre parece que tengo problemas para encontrar esta pregunta / respuesta, así que decidí preguntar / responder yo mismo. Se aceptan explicaciones / respuestas adicionales.
thealexbaron
Otro ejemplo son los elementos de navegación
Tjorriemorrie

Respuestas:

66

Esta es una limitación actualmente, pero probablemente se solucionará en algún momento en el futuro ( hay algunos problemas abiertos en el repositorio de github ).

Por ahora, puede usar una función que devuelva una matriz (este es básicamente un componente sin estado):

function things(arg, onWhatever){
    return [
        <tr><td>Item 1</td></tr>,
        <tr><td>Item 2</td></tr>
    ];
}

Y utilícelo en su componente.

return (
    <table><tbody>
      {things(arg1, this.handleWhatever)}
      {things(arg2, this.handleWhatever)}
    </tbody></table>
);

Actualizar

En React 16 podrás devolver una matriz de render.

Otra actualización

Ahora puede devolver una matriz de nivel superior o usar <React.Fragment>.

Con una matriz, necesitamos colocar una clave en cada elemento, ya que React no sabe que los dos elementos son constantes, en lugar de una lista creada dinámicamente:

function RowPair() {
  return [
    <tr key="first"><td>First</td></tr>,
    <tr key="second"><td>Second</td></tr>,
  ]
}

Con React.Fragment, se comporta mucho más como envolverlo en a <div>o similar, donde keyno se requiere a si no estamos construyendo los niños dinámicamente. Primero, podemos envolver la matriz en un Fragmento:

function RowPair() {
  return <React.Fragment>{[
    <tr key="first"><td>First</td></tr>,
    <tr key="second"><td>Second</td></tr>,
  ]}</React.Fragment>
}

Y luego podemos eliminar la matriz keyys por completo:

function RowPair() {
  return <React.Fragment>
    <tr><td>First</td></tr>
    <tr><td>Second</td></tr>
  </React.Fragment>
}
Bandido
fuente
2
¿Por qué todos dicen que esto funciona ???? Error no detectado: x.render (): Se debe devolver un elemento React válido (o nulo). Es posible que haya devuelto undefined, una matriz o algún otro objeto no válido.
Xogle
@Xogle Algo debe haber cambiado en la API de React. Parece que ya no funciona.
Petr Peller
1
@FakeRainBrigand Veo el problema. No es un "componente sin estado", es una función que devuelve una matriz. Los componentes sin estado no pueden devolver matrices y no puede conectar una función simple a la tienda Redux.
Petr Peller
@PetrPeller ¿estás usando jsx? En el ejemplo, lo llamo como una función.
Brigand
No entiendo todos los votos a favor, esto no responde la pregunta en absoluto. La pregunta es cómo representar elementos hermanos sin un elemento principal y esta respuesta aún representa un elemento principal.
Dancrumb
33

Sé que esta ha sido una publicación antigua, pero tal vez mi respuesta pueda ser de ayuda para principiantes como yo.

En React 16.2, se agregó soporte mejorado para Fragments .

Ahora puede devolverlo así:

return (
  <>
    <tr><td>Item 1</td></tr>
    <tr><td>Item 2</td></tr>
  </>
);

Puedes envolverlo con <></>o <Fragment></Fragment>.

Si desea pasar algunos atributos, solo se admite la clave al momento de escribir, y tendrá que usarla <Fragment />ya que la sintaxis corta<></> no acepta atributos.

Nota: Si va a utilizar la sintaxis corta, asegúrese de que está utilizando Babel 7 .

Referencia de fuente

onoya
fuente
1
Exactamente lo que buscaba, gracias! Además, en caso de que nadie más lo necesita: importación Reaccionar, {} Fragmento de 'reaccionar'
Chris
Parece que no puedo encontrar la implementación de Fragmenten su repositorio, ¿puede alguien, por favor, mostrarme? Gracias :)
Ramon Balthazar
No puedo hacer que funcione, incluso si instalo Babel-cli ... incluso solo para la solución <>. ¿Cómo es posible @onoya? Estaré publicando un hilo pronto,
Gaelle
3

Tener un elemento padre es útil en la mayoría de los casos, como por ejemplo, puede tener un className padre que puede apuntar al estilo de los elementos secundarios y algunos otros escenarios ...

Pero, si realmente no quiere hacer eso, puede usar React.Fragment

Así que simplemente haz algo como esto:

<React.Fragment>
  <First />
  <Second />
  <Third />
</React.Fragment>

A partir de la versión 16.2 , también hay una versión abreviada <>que se ve así en la función de renderizado:

render() {
  return (
    <>
      <First />
      <Second />
      <Third />
    </>
  );
}

Además, si usa la versión 16.0 y superior, puede devolver una matriz de elementos que no necesita un contenedor principal, como se muestra a continuación:

render() {
 return [
  <h1 key="heading">Hello from Alireza!</h1>,
  <p key="first">Here where I'm!</p>,
  <p key="second">And again here :)</p>
 ];
}
Alireza
fuente
0

Puede ajustarlo a los corchetes de esta manera:

React.createClass({
    render: function() {
        return (
          [
            <tr><td>Item 1</td></tr>
            <tr><td>Item 2</td></tr>
          ]
        );
    }
});
Vitaliy Andrusishyn
fuente
¿Qué tal si también necesita usar Object.keys()dentro de la devolución?
Juha Untinen
P.ej. return ( [ <tr><td>Header</td></tr>{ Object.keys(this.props.data).map(function(item) { <tr><td>{data}</td></tr> }) } ] ); Con 15.4.2, cede Unexpected token, expected ,en la llave de apertura dentro de la vuelta
Juha Untinen
intente algo como esto: return ({Object.keys (this.props.data) .map (function (item) {<tr><td>{data}</td> </tr>}). unshift ({< tr> <td> Encabezado </td> </tr>})});
Vitaliy Andrusishyn
Esto no funciona, aún debe tener una coma que separe <tr> -s
Philipp Munin
0

Este ejemplo funciona bien para mí:

let values = [];

if (props.Values){
  values = [
    <tr key={1}>
      <td>props.Values[0].SomeValue</td>
    </tr>
  ,
    <tr key={2}>
        <td>props.Values[1].SomeValue</td>
        </tr>
    ];
}

return (
    <table className="no-border-table table">
      <tbody>
        <tr>
            <th>Some text</th>
        </tr>
        {values}
      </tbody>
    </table>
)
MrDuDuDu
fuente
0

Algo como esta sintaxis funcionó para mí

this.props.map((data,index)=>{return( [ <tr>....</tr>,<tr>....</tr>];)});
Superve
fuente
-2

Para aquellos que usan TypeScript, la sintaxis correcta es:

return [
  (
    <div>Foo</div>
  ),
  (
    <div>Bar</div>
  )
];
0 pierna
fuente
1
Esto es idéntico a la respuesta de @thealexbaron y no tiene nada que ver con TypeScript
andrewarchi