React: Agregue la API de fragmentos para permitir la devolución de múltiples componentes del renderizado

Creado en 2 sept. 2014  ·  148Comentarios  ·  Fuente: facebook/react


Nota de los mantenedores:

Sabemos que esto es un problema y sabemos exactamente qué conjunto de problemas se puede resolver. Nosotros también queremos esto, pero es un _problema difícil_ con nuestra arquitectura actual. Los comentarios adicionales que expresan el deseo de esta función no son útiles. Siéntase libre de suscribirse al problema (hay un botón en la columna de la derecha), pero no comente a menos que esté agregando valor a la discusión. "Yo también" y "+1" no son valiosos, ni son casos de uso que ya se hayan escrito en los comentarios (por ejemplo, sabemos que no puede poner elementos <tr> o <dd> con <div> ).


Considera lo siguiente:

var ManagePost = React.createClass({

  render: function() {
    var posts = this.props.posts

    var something;
    var somethingelse;

    var row = posts.map(function(post){
      return(
        <div>
          <div className="col-md-8">
          </div>
          <div className="cold-md-4">
          </div>
        </div>
      )
    });

    return (
        {row}
    );
  }

});

Si elimina <div></div> en map , obtendrá el siguiente error: _Los elementos XJS adyacentes deben estar envueltos en una etiqueta adjunta_

no es hasta que vuelvo a agregar los divs circundantes, y bastante inútiles, que se compila sin problemas. Estoy ejecutando 0.11.1

¿Se está abordando esto? Agrega más, y nuevamente, en mi opinión, html inútil y sin sentido a la página, que aunque no daña nada, se ve desordenado y poco profesional. Tal vez solo estoy haciendo algo mal, por favor ilumíname si es así.

Comentario más útil

Creo que podemos cerrar esto.

La devolución de matrices desde los componentes es compatible desde React 16 Beta 1, que puede probar ahora .

Todavía hay algunas limitaciones (la compatibilidad con SSR no está lista), pero las estamos rastreando en el n.º 8854 y las solucionaremos antes de la versión final 16.

¡Gracias a todos por sus comentarios!

Todos 148 comentarios

Porque cuando no le pones el envoltorio, se desazuca a esto:

return React.DOM.div(...)React.DOM.div(...)

Lo cual no tiene sentido sintáctico. La página del compilador jsx podría ayudar si necesita un mapeo visual.

Dicho esto, es posible quitarle el azúcar a [div, div] en su lugar. Esto es difícil, algo controvertido y no se implementará en un futuro cercano.

(No creo que sea particularmente controvertido, pero agrega complejidad al código y aún no se ha hecho).

IIRC @syranide tiene algunos comentarios sobre esto

@chenglou Jeje.

Tuve una breve conversación al respecto con chenglou hace un rato, realmente no me inclino por un lado u otro en este momento. Veo muchos peligros ocultos al permitir que los componentes compuestos devuelvan múltiples componentes y rompe muchas suposiciones intuitivas, pero no conozco ningún caso de uso de buenas prácticas (en este momento) que obviamente se beneficiaría de esto.

La simplicidad de devolver como máximo un componente significa que es muy fácil razonar sobre lo que ve, si no, <table><TableHeader /></table> en realidad podría generar cualquier cantidad de filas, no tiene forma de saberlo más que inspeccionar TableHeader y cualquier componente compuesto que devuelva.

Siento que poder devolver múltiples componentes solo mueve la responsabilidad de envolver los componentes según sea necesario del "componente compuesto" a lo que sea que "representa el componente compuesto". El componente "que convierte el componente compuesto" rara vez tiene o debería tener el conocimiento de si envolver componentes compuestos o no, mientras que es más probable que los niños tengan conocimiento de sus padres.

Pero tal vez sea simplemente un caso de responsabilidad del desarrollador. Puede haber buenos casos de uso para ambos y deberíamos mirar más allá del inevitable mal uso.

@sebmarkbage Probablemente también tenga algunos comentarios :)

Probablemente nunca permitiremos esa sintaxis implícitamente. Necesitarías un envoltorio como

<>
  <div className="col-md-8">
  </div>
  <div className="cold-md-4">
  </div>
</>

O

[
  <div className="col-md-8">
  </div>,
  <div className="cold-md-4">
  </div>
]

Sin embargo, incluso esto no funciona. A menudo, es probablemente lo mejor. Puede ser confuso consumir componentes cuando un niño puede expandirse en múltiples elementos.

Pero, realmente, la única razón por la que no apoyamos esto en este momento es porque es difícil de implementar. Con suerte, podremos admitirlo en algún momento en el futuro, pero probablemente no a corto plazo. Lo siento. :/

¿Esto no puede afectar cosas como jquery u otras bibliotecas que apuntan a elementos específicos? Entonces, si hace algo como $('#id-name').children() , lo siguiente:

<div id="id-name">
  <div>
    <div class="class-name">
    </div>
  </div>
</div>

en este caso se seleccionarían <div> y <div class="class-name"> . (Si entiendo bien esto)

Afecta también a los selectores de css de la misma manera que @AdamKyle publicó antes.

¿Alguna actualización sobre este tema?

Pasé un par de minutos entendiendo por qué mi componente no funcionaba. Siento que debería haber un aviso en alguna parte, ¿tal vez me lo perdí? Tal vez es obviamente un error intentarlo:

var Optimistic = React.createClass({
  render: function() {
    return ( 
      <h1>{this.props.name} loves React</h1>
      <p>React doesn’t. Idea: sprinkle some divs here and there.</p>
    );
  }
});

React.render(
  <Optimistic name="Peter" />,
  document.getElementById('myContainer')
);

@gabssnake Debería haber recibido un error de compilación JSX con el error "Los elementos XJS adyacentes deben estar envueltos en una etiqueta envolvente"; no viste el error o no te quedó claro en su explicación?

Gracias por tu respuesta @spicyj. Bueno, me refiero a un aviso en la documentación de React. Sí, la consola mostró un error, pero la necesidad de envolver no tenía sentido para mí al principio. Por eso busqué y llegué aquí.

Yo también he tenido este dolor... particularmente doloroso para mi diseñador, de hecho. Sería bueno si un componente pudiera generar un nodo (por lo tanto, una lista de nodos o un fragmento) en lugar de un elemento.

Solo digo ... No estoy defendiendo la devolución de varios niños del componente _pero_ Me encantaría hacerlo en los métodos render* que extraigo de render :

  render: function () {
    return (
      <div className={this.getClassName()}
           style={{
             color: this.props.color,
             backgroundColor: this.props.backgroundColor
           }}>
        {condition ?
          this.renderSomething() :
          this.renderOtherThing()
        }
      </div>
    );
  },

  renderSomething() {
    return (
      <>
        <div className='AboutSection-header'>
          <h1>{this.props.title}</h1>
          {this.props.subtitle &&
            <h4>{this.props.subtitle}</h4>
          }
        </div>,

        {hasChildren &&
          <div className='AboutSection-extra'>
            {this.props.children}
          </div>
        }
      </>
    );
  }

Pero probablemente debería callarme y usar key s.

@gaearon Sin embargo, ya puede hacer eso, solo necesita devolver una matriz por ahora (que es un poco engorroso, aunque sí) ... pero, puede solucionar eso, he pirateado mi propio componente <Frag> que se traduce en una matriz (sobrecargado React.render ) ... también podría hacer return <NoopComp>...</NoopComp>.props.children , supongo, si quiere evitar hacks.

EDITAR: Mi error, sobrecargué React.createElement no React.render .

El problema con las matrices es que hacen tropezar a nuestro diseñador. Necesita comas, claves explícitas.

@gaearon Sí, puedes evitar las comas usando cualquiera de mis dos soluciones por ahora (si encuentras alguna aceptable)... pero ¿qué quieres decir con claves explícitas?

Si uso la sintaxis de matriz, necesito especificar key en cada elemento. No es que sea difícil de hacer, pero se siente incómodo porque sé que nunca cambian.

@gaearon Ah, sí, elijo ignorar mentalmente esa advertencia por ahora :), si realmente quieres evitarlo, puedes hacer <MyComp children={this.renderWhatever()} /> para evitarlo ( EDIT: aunque obviamente no puedes usar eso si tiene hijos adyacentes, podría usar algún ayudante de aplanamiento ... pero sí).

Otro caso con el que me encontré con un kit de interfaz de usuario. Cuando coloca a los niños dentro de un contenedor desplazable fijo como este:

return (
  <div style={{
    position: fixed
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: scroll;
  }}>
    {this.props.children}
  </div>
);

Los elementos secundarios ahora deben pasarse como una matriz, pero si se pasa una clase compuesta, también debe implementar esos estilos para evitar romperla. Solo agrega una capa de complejidad. Pero puedo entender completamente lo complejo que debe ser hacer el cambio. Solo tiro mi sombrero en busca de apoyo.

Tengo otro caso de uso que describí en detalle aquí #3415. Pero puedo solucionarlo por ahora y entiendo que es difícil de implementar y raro.

No sé nada sobre los elementos internos de reacción (todavía), pero solo daré una idea de cómo podría marcar dichos elementos/fragmentos principales virtuales en el DOM: comentarios. P.ej

<A>
    <B></B>
    <Fragment>
        <C></C>
        <D></D>
    </Fragment>
    <E></E>
</A>

rendiría a

<a>
    <b></b>
    <!--<fragment data-reactid="">-->
        <c></c>
        <d></d>
    <!--</fragment>-->
    <e></e>
</a>

Esto significa que c y d serán tratados como hijos de algo. (incluido el reactid anidado para que no entre en conflicto con b y e). He visto comentarios de "uso indebido" de otros marcos para este tipo de trabajos semánticos.

@Prinzhorn Creo que podría estar confundiendo la salida DOM con JSX de React.

En caso de que sea útil: la sugerencia de @Prinzhorn de usar comentarios HTML para asignar "componentes de fragmentos" al DOM es el mismo enfoque que usa Knockout. Knockout llama a estos "elementos virtuales".

<!-- ko component: "message-editor" -->
<!-- /ko -->

(de documentos knockout )

Además, otro caso de uso para esto: los elementos de envoltura adicionales pueden ser problemáticos cuando se usa flexbox.

@aldendaniels absolutamente de acuerdo, ya me he encontrado con problemas de flexbox.

Me encontré con esto con flexbox con menús desplegables dependientes. Donde A representaría y administraría el primer menú desplegable, seguido de B, C o D según el valor del menú desplegable de A, cada uno de los cuales generaría la cantidad adecuada de menús desplegables, por ejemplo

<A>
 <Drop />
 <C><Drop /><Drop /></C>
</A>

A, B, C y D no tienen estado, así que los cambié de class B {render(){ this.props }} a function B(props){ return [...]; } .

En este caso, no le importa mucho al padre que se representen varios niños, es solo para lidiar con mi CSS. Hay cosas que haría de manera diferente si no fuera necesario reutilizarlas (otro componente necesita B, C y D).


Como alternativa, ¿tal vez una forma de desentrañarlo del padre? No tengo ninguna idea específica de cómo se vería eso.

Hoy me encontré con un escenario que creo que es un buen caso de uso para esta característica: un componente que representa múltiples elementos <script> , donde podría representar el elemento <head> de la página. Cualquier elemento de envoltura allí sería malo.

Mi escenario es querer tener un componente que sea responsable de representar la etiqueta <script> tanto para el código de tiempo de ejecución necesario en la página como para otra etiqueta <script> que lleve las cadenas localizadas para ser utilizadas por el código de tiempo de ejecución. Por ejemplo:

<html>
    <head>
        <script language="runtime.resources.en-us.js"></script>
        <script language="runtime.js"></script>
    </head>
    <body>
    ...
    </body>
</html>

En este caso, me gustaría tener el código creado como:

var RuntimeScripts = require('./Runtime')
...
return (
    <html>
        <head>
            <RuntimeScripts language="en-us" />
        </head>
    </html>
)
...

También me encontré con algunos problemas de flexbox. Nada que no se pueda resolver en CSS, pero una de las "bellezas" de flexbox es que necesita menos elementos de "envoltura" en todas partes para que su diseño funcione, pero aún terminará con elementos de envoltura en todas partes cuando use React desde siempre envuelve lo que devuelve en div/div o similar, a menos que tenga sentido tener un contenedor.

Para todos los casos de uso presentados aquí, estoy bastante seguro de que podría reemplazar <BunchOfComponents /> con {getBunchOfComponents()} y la salida visual sería la misma, sin introducir los problemas prácticos y técnicos relacionados con tener componentes con fragmentos como raíz.

@syranide, pero cada vez que uno de los componentes cambia, todos sus hermanos necesitan volver a calcularse...

Además, si usa un script de café simple, es fácil devolver una matriz, así que separe la funcionalidad de la representación jsx.
IOW, si es fácil manejar una matriz de elementos devuelta, no espere a que jsx se ponga al día.

@syranide, pero cada vez que uno de los componentes cambia, todos sus hermanos necesitan volver a calcularse...

@wmertens Sí, pero muchas veces tendría eso de todos modos porque el padre necesitaría volver a procesar por otras razones, o simplemente porque recibe los datos a través de accesorios de todos modos. Pero sí, esa es la diferencia, pero no significa que este enfoque sea correcto, es una optimización y hay muchas formas de lograrlo.

Además, si usa un script de café simple, es fácil devolver una matriz, así que separe la funcionalidad de la representación jsx.

Eso es irrelevante y esto no es un problema con JSX. Un gran problema es que pierde la suposición técnica, práctica e intuitiva de un componente = un elemento/nodo . No puedo hablar por los desarrolladores, pero no renunciaría a eso de buena gana, es una suposición muy útil. Estoy seguro de que hay optimizaciones igualmente buenas o mejores que podrían diseñarse si la optimización es la única razón por la que la gente quiere esto.

@syranide, el mayor problema es que no siempre puedes usar una envoltura
elemento en html, como en tablas, listas, flexbox, head... Trabajar alrededor
eso conduce a un código feo.

Estaría perfectamente feliz con un elemento contenedor virtual que solo representa
comentarios, como se sugirió anteriormente.

El viernes 29 de mayo de 2015 a las 15:56 Andreas Svensson [email protected]
escribió:

@syranide https://github.com/syranide pero cada vez que uno de los
los componentes cambian todos sus hermanos necesitan recalcularse...

@wmertens https://github.com/wmertens Sí, pero muchas veces lo harías
tener eso de todos modos porque el padre tendría que volver a renderizar para otros
razones, o simplemente porque recibe los datos a través de accesorios de todos modos. Pero
sí, esa es la diferencia, pero no significa que este enfoque sea correcto,
es una optimización y hay muchas formas de lograrlo.

Además, si usa un script de café simple, es fácil devolver una matriz, así que por favor
desacople la funcionalidad de la representación jsx.

Eso es irrelevante y esto no es un problema con JSX. Un gran problema es que
se pierde el supuesto técnico, práctico e intuitivo de _one
componente = un elemento/nodo_. No puedo hablar por los desarrolladores, pero no lo haría.
renunciar a eso voluntariamente, es una suposición muy útil. Estoy seguro
hay optimizaciones igualmente buenas o mejores que podrían diseñarse si
la optimización es la única razón por la que la gente quiere esto.


Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/facebook/react/issues/2127#issuecomment-106810565 .

Por cierto, es relativamente fácil piratear un componente de "fragmento" en React que React trata como una matriz de sus elementos secundarios. Generará claves automáticamente, pero dado que ocurre después de la validación inicial de los componentes, no arrojará el error habitual de "no se proporcionaron claves".

Dicho esto, ese truco solo resuelve lo que @gaearon estaba hablando anteriormente, no tener que lidiar con la sintaxis de matriz fea/establecer claves arbitrarias en su JSX, y no el problema de devolver múltiples nodos en la raíz del método de renderizado de un componente.

Tengo un problema con la idea de que un componente necesita devolver un "elemento/nodo". Para mí, parece perfectamente razonable para una estructura JSX de:

<Main>
  <Foo />
  <Fragment>
    <Bar />
    <Baz />
  </Fragment>
</Main>

para terminar como el DOM:

<div>
  <div>Foo</div>
  <div>Bar</div>
  <div>Baz</div>
</div>

No creo que esto sea una violación del principio de la menor sorpresa porque los componentes ya hacen todo tipo de "cosas sorprendentes" con el DOM usando ganchos de ciclo de vida (solo mire el patrón de agujero de gusano común). En general, se acepta que un componente no necesariamente dará como resultado la creación de un solo elemento, y eso está bien, porque se deben hacer algunos compromisos para trabajar con el DOM.

No se trata de "optimizaciones", ni siquiera de que no le guste la sintaxis de matriz. Como han mencionado muchos usuarios, los elementos _wrapper rompen el estilo y el diseño de manera seria_. Las tablas son las más obvias, pero Flexbox también es un problema importante. Ya tengo CSS que solo vuelve a aplicar reglas flexibles a los elementos de envoltura que solo existen gracias a React, y es bastante feo.

Para todos los casos de uso presentados aquí, estoy bastante seguro de que podría reemplazar con {getBunchOfComponents()} y la salida visual sería la misma, sin introducir los problemas prácticos y técnicos relacionados con tener componentes con fragmentos como raíz.

Esto requiere que los desarrolladores se comprometan a crear componentes aislados y reutilizables (el cielo los ayude si deciden que quieren reutilizar su grupo de componentes en otro lugar) debido a un problema de implementación subyacente en React. No creo que eso deba aceptarse.

@thomasboyt

EDITAR: Mi error, combiné algunos de sus argumentos con la discusión de la mesa anterior, estoy en gran medida de acuerdo con lo que dice, creo. Pero todavía hay problemas con los componentes que son opacos, por lo que lo que pretende ser un envoltorio transparente útil se vuelve opaco para el padre. Imagine que <Wrapper1><Wrapper2>...</Wrapper2></Wrapper1> , Wrapper1 no puede ver a los hijos de Wrapper2 . Entonces, tal vez wrapMyElements(...) simplemente sea una mejor solución en general (incluida cualquier otra funcionalidad de soporte necesaria).

Tengo un problema con la idea de que un componente necesita devolver un "elemento/nodo". Para mí, parece perfectamente razonable para una estructura JSX de:

Los componentes son más que envoltorios tontos, tienen un propósito. En mi humilde opinión, parece que devolver varios elementos bloquea algunas expectativas muy útiles. Por ejemplo, React.render obtendrá un compañero en el futuro que represente un elemento y devuelva los nodos, esto ahora debe producir una matriz de nodos en su lugar.

Pero creo que un tema muy importante es la legibilidad, que en mi humilde opinión es el mayor punto de venta de React, todo es explícito.

<table>
  <tr>
    <td />
    <td />
    <td />
  </tr>
  <tr>
    <Columns1 />
    <Columns2 />
  </tr>
</table>

Mirando eso, no tiene sentido, ¿de dónde viene la tercera celda? Tal vez en realidad está mal y está renderizando 2 o 4 celdas, quién sabe, ¿tal vez en realidad es dinámico y depende de un accesorio o estado externo? Hay muchas variaciones de este problema que solo se vuelven más difíciles cuando se consideran otras interfaces que no son HTMLDOM que pueden tener expectativas explícitas. Otra cosa a considerar es que los elementos son opacos, por lo que si reemplaza <tr /> con <MyMagicalTr /> , entonces no podrá interactuar con las celdas individuales o incluso deducir cuántas hay, por lo que aunque <MyMagicalTr /> solo puede aceptar <MyMagicalTd /> , no hay garantía de que realmente pueda interactuar con ellos.

Esto requiere que los desarrolladores se comprometan a crear componentes aislados y reutilizables (el cielo los ayude si deciden que quieren reutilizar su grupo de componentes en otro lugar) debido a un problema de implementación subyacente en React. No creo que eso deba aceptarse.

"Esto requiere que los desarrolladores se comprometan a hacer aislado...", pero ese es exactamente el problema si me preguntas, si un componente puede devolver múltiples elementos, ya no está aislado, se sustituye, el componente se está filtrando al padre.

Clavos. Al ser un problema de implementación subyacente, es un problema separado de si esto debería hacerse o no. No es mi decisión, pero no veo cómo un caso de uso raro es un argumento convincente sin considerar las compensaciones que conlleva o qué otras soluciones alternativas existen.

En mi humilde opinión, no veo el problema con {getBunchOfComponents()} , es explícito, nos permite mantener nuestras expectativas útiles. Si el rendimiento es un problema, entonces React.createSmartFragment() (o w/e) al rescate, una matriz transparente/tipo similar a un objeto pero que puede actualizarse independientemente de su padre.

Nuevamente, los desarrolladores de React son la autoridad (no yo), pero no veo un argumento convincente aquí considerando los diversos efectos secundarios. Ni siquiera estoy seguro de estar de acuerdo con que la solución presentada sea un buen patrón, incluso si fuera compatible.

EDITAR: para aclarar, quizás los componentes puedan devolver múltiples elementos en el futuro porque hay otros casos de uso obviamente beneficiosos, especialmente en el contexto de pasar a través de niños (como el que le muestra a @thomasboyt), se mantiene la legibilidad.

Creo que necesitaré un poco más de café antes de poder responder al lado filosófico de esta conversación (gracias por los muy buenos puntos, @syranide), pero en el lado de la implementación, comencé a hurgar en esto anoche para ver cómo es viable un cambio de este alcance, lo que lleva a este pico: https://github.com/facebook/react/compare/master...thomasboyt:fragment

Y lanzó una pequeña demostración aquí: http://www.thomasboyt.com/react-fragment-demo/

Algunas observaciones sobre el lado de la implementación de las cosas:

  • No es sorprendente que sea muy complicado adaptar un sistema que espera que "1 componente = 1 nodo" admita más nodos;)
  • Inicialmente pensé en intentar rastrear fragmentos en el lado de las operaciones DOM, de modo que las instrucciones de mutación generadas por ReactMultiChild pudieran permanecer iguales y tratar fragmentos como cualquier otro nodo. Sin embargo, no pude pensar en una buena manera de agregar el estado sobre los recuentos de nodos/qué nodos son fragmentos en el seguimiento del estado DOM. Algo como el comentario de vallado que señaló @Prinzhorn podría funcionar, pero desconfío de cualquier cosa que requiera una búsqueda de DOM, considerando el costo relativo.
  • Con esa idea descartada, agregué un campo _nodeCount a todos los elementos secundarios de un componente ReactMultiChild , de modo que pudiera rastrear la cantidad de nodos raíz que contiene realmente un fragmento.

El problema es que, si bien esto es bastante fácil de hacer en un renderizado inicial simplemente contando los hijos de un fragmento, actualizar el recuento de nodos del fragmento en mutaciones posteriores parece más complicado. Esto todavía no se hace en mi sucursal (consulte https://github.com/thomasboyt/react/issues/2).

  • Muchas operaciones DOM se basan en acceder al nodo principal de un elemento, buscado por el ID de nodo interno, para agregar/mover/eliminar elementos (ver https://github.com/thomasboyt/react/issues/3). Dado que el ciclo updateComponent ReactMultiChild es responsable de pasar este ID, podría cambiarse para hacer una búsqueda del padre más cercano que tiene un nodo DOM, pero eso suena costoso. Alternativamente, puede ser posible tener un registro interno de claves de fragmento para sus claves de "nodo real".

Todavía no estoy convencido de que requerir fragmentos para mantener un recuento de sus nodos raíz sea la mejor manera de hacer esto (aunque al menos me llevó a esa demostración), y todo esto fue pirateado con bastante rapidez y bastante tarde en la noche. , por lo que si alguien más tiene una sugerencia para la implementación, siéntase libre de participar:>

@thomasboyt IIRC, el principal obstáculo de implementación proviene de React que hace referencia a los nodos secundarios por mountIndex , esto no funciona cuando un "nodo" puede convertirse repentinamente en cualquier cantidad de nodos y esto puede suceder sin invocar al padre y también puede suceder varios componentes de profundidad (envoltura). Si no me equivoco, es bastante trivial que React admita múltiples elementos raíz siempre que el número nunca cambie.

Por lo tanto, no creo que sea especialmente difícil hacer que funcione en React, pero una solución verdaderamente adecuada es más problemática y probablemente debería implicar soltar mountIndex .

@syranide Correcto; la solución en la que estoy trabajando en realidad presenta un nuevo nodeIndex que se supone que es el "desplazamiento real" de un nodo (lo que me recuerda que necesito volver atrás y eliminar mountIndex , ya que Creo que ahora no se usa en mi sucursal).

Pero, como observa, esto es problemático si cambia la cantidad de elementos raíz, ya que el nodeIndex de un componente debe actualizarse cada vez que cambia el recuento de nodos de un componente hermano anterior. Todavía necesito encontrar una solución para eso.

También me he encontrado con problemas de flexbox. @syranide , ¿podría elaborar un poco más sobre su solución propuesta "getBunchOfComponents"? Al ser nuevo en React, es difícil tener una idea completa de dónde definir esta función / cómo aplicarla.

@landabaso

function getBunchOfComponents(...) {
  return [<ColumnA key="a" />, <ColumnB key="b" />];
}

Oye,

No he leído todo el hilo, pero aquí hay un caso de uso de optimización de procesamiento que puede requerir esta función:

http://stackoverflow.com/questions/30976722/react-performance-rendering-big-list-with-purerendermixin

Si se lanza esta función, ReactCSSTransitionGroup ya no necesitará un nodo contenedor, ¿verdad?

@slorber Sí, eso es probablemente cierto.

Ejecute la necesidad de esta función todos los días.

Si tiene muchos componentes pequeños (es decir, un diseño muy modular), termina teniendo que envolver todo tipo de cosas en divs que no deberían estar. Podría estar confundiendo, pero creo que esto se relaciona con este problema.

Para <div> , puede envolverlos en un <div> , pero para los elementos de las filas de la tabla <tr> , no es tan fácil. Puede envolver <tr> en <tbody> , pero puede que no sea conveniente tener varias capas de <tbody> envolviendo varias capas de <tr> .

El escenario que mencioné era tratar de tener un componente que proporcione elementos <link> y <script> sin tener que convertirse en el renderizador <head> por completo.

Agregué una nota al principio de este problema. Por favor, léalo antes de comentar. https://github.com/facebook/react/issues/2127#issue -41668009

Bump... Tengo una gran necesidad en el lado del servidor. Es muy complicado renderizar páginas web completas (excluyendo doctype) sin la capacidad de renderizar fragmentos, debido a la sección <head> . Actualmente estoy solucionando eso a través de mixins y un poco de lógica en el renderizado final, pero sería mucho más simple si hubiera soporte para renderizar múltiples componentes.

@impinball puede intentar escribir algo similar a react-document-title basado en react-side-effect para resolver estos problemas. Pude hacer lo mismo con las metaetiquetas, los encabezados, el título y, en ocasiones, los redireccionamientos.

También tengo este problema, ¿hay alguna solución por el momento? No pude hacer que {getBunchOfComponents()} funcionara como se sugiere.

Nada menos que los ya mencionados.

@jonchay Podría crear un componente que solo represente a sus hijos.

function statelessWrapper(props) {
   return props.children;
}

y luego para usarlo:

render() {
   return (  
      <statelessWrapper>
         {renderABunchOfComponents()}
      </statelessWrapper>
    );
}

@whatknight Eso no funcionará, excepto en los casos en que return renderABunchOfComponents(); ya funcione.

  render () {
    let user = this.state.user
    let profile = user.get('data')
    let view = null

    if (user.get('status') === 'fetched') {
      view = (
        <h1>{profile.get('login')}</h1>
        <img src={profile.get('avatar_url')} />
        <dl>
          <dt>email</dt>
          <dd>{profile.get('email')}</dd>
        </dl>
      )
    } else if (user.get('status') === 'fetching') {
      view = <h1>fetching</h1>
    } else if (user.get('status') === 'error') {
      view = <h1>{profile.message}</h1>
    }

    return (
      <div className={className}>
        {view}
      </div>
    )
  }

Al menos debería haber una forma de devolver múltiples fragmentos mientras se realiza la interpolación y el "ensamblaje". El ejemplo anterior se queja de que img y h1 son adyacentes, pero terminarán estando dentro del envoltorio principal de todos modos. Ese es un elemento envolvente del que desearía poder deshacerme.

@kilianc en este caso, simplemente puede escribir

      view = [
        <h1 key={0}>{profile.get('login')}</h1>,
        <img key={1} src={profile.get('avatar_url')} />,
        <dl key={2}>
          <dt>email</dt>
          <dd>{profile.get('email')}</dd>
        </dl>,
      ]

la forma en que lo está usando, no hará una diferencia si este problema se resuelve.

Necesito esta función por las razones ya mencionadas, así que intenté implementar un contenedor <frag></frag> en https://github.com/mwiencek/react/tree/frag-component

La implementación no es realmente bonita, pero si funciona para las personas, puedo enviar un PR y dejar que los desarrolladores de React lo destrocen.

@mwiencek Parece que su implementación no funciona si la cantidad de niños en un fragmento cambia en una actualización (_nestedChildCount se establece solo en mountComponent)? Hay un pequeño truco para que todo funcione bien. Aunque parece que has tenido un buen comienzo. De hecho, he estado pensando en esto nuevamente recientemente y es posible que haya descubierto una forma sólida de hacer que esto suceda. Informaré si encuentro el éxito.

@spicyj sí , tienes razón, tendré que investigar eso...

Sin embargo, estoy muy emocionado de que podamos ver una implementación adecuada pronto. :) Siéntase libre de copiar las pruebas de esa rama si son de alguna utilidad.

@spicyj ¿No es el camino a seguir para usar createFragment y hacer que JSX se transforme en eso? ¿O realmente queremos que los fragmentos sean elementos?

Para construir y ampliar el último comentario de @syranide , parece que no hay necesidad de una "API de fragmentos" adicional si el renderizado permite matrices como valor de retorno. JSX podría transformar múltiples elementos raíz en una matriz, lo que también funcionaría para los valores de retorno de cualquier otra función. Entonces, en lugar de introducir una superficie API adicional, que requiere documentación y aprendizaje, una de las limitaciones de React podría eliminarse.

Esto afectaría al menos a babel-plugin-transform-react-jsx (implementación) y también a babel-plugin-syntax-jsx (eliminación del error de análisis para elementos raíz adyacentes). Si bien cambiar el primero parece ser bastante seguro, no sé el alcance/uso del último y el impacto que tendría el cambio propuesto en otros proyectos.

Eso todavía no cubre el caso de uso de un condicional con múltiples elementos. No considero que "Usar una matriz y agregar manualmente un key={...} arbitrario a cada elemento" sea una solución adecuada a largo plazo.

de acuerdo con @dantman

sí, buen punto. La generación automática de claves debe incorporarse a través de la transformación. Usar el índice de matriz como clave debería ser suficiente, ya que los elementos no cambian.

En cuanto a los condicionales, esto también podría integrarse en la transformación o, alternativamente, podría usar JSX-Control-Statements . Lo implementé allí de esta manera, de ahí la idea.

Para manejar las actualizaciones correctamente, pensé que la solución que @spicyj pensó para #5753 también podría funcionar para fragmentos (envolviendo el contenido en algo como <!-- react-frag: 1 --><!-- /react-frag: 1 --> ). Sí, los comentarios son un poco feos, pero es mucho más confiable que lo que estaba tratando de hacer con _nestedChildCount . Ese enfoque es ahora lo que se usa en https://github.com/mwiencek/react/tree/frag-component

No he visto esto mencionado en el hilo hasta ahora, pero creo que resolver esto también mejora la composición. Por ejemplo, imagine que tiene una cuadrícula en la que desea que las celdas se desvanezcan en un orden determinado. Idealmente, habría dos componentes en juego aquí: uno para manejar el diseño y otro para manejar la animación. Tendrías una API como esta:

<GridLayout
  columns = { 3 }
>
  <FadeAnimator
    springConfig = { springConfig }
  >
    { ...cells }
  </FadeAnimator>
</GridLayout>

Esto le permitiría cambiar a un diseño diferente, o una animación diferente, sin que uno tenga que conocer los detalles de implementación del otro. GridLayout esperaría recibir una lista de niños. FadeAnimator interceptaría esa lista, inyectaría los estilos apropiados y/o detectores de eventos, y devolvería la nueva lista para que la consuma GridLayout . No hay ninguna razón para que FadeAnimator se preocupe por diseñar una cuadrícula, excepto que los elementos React no pueden devolver Arrays desde el renderizado. Además, no existe una manera simple de reemplazar la cuadrícula con, digamos, un diseño de mampostería, porque se requiere que FadeAnimator actúe como un contenedor para sus elementos secundarios.

Con las limitaciones actuales, supongo que podrías hacer algo como esto:

<FadeAnimator
  wrapper = {
    <GridLayout
      columns = { 3 }
    />
  }
  springConfig = { springConfig }
>
  { ...cells }
</FadeAnimator>

// FadeAnimator
render() {
  return React.cloneElement(
    props.wrapper,
    null,
    props.children
  );
}

pero eso hace que el código sea menos claro, más complejo y más difícil de componer.

Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!
Agregue una API de fragmentos para permitir la devolución de múltiples componentes del renderizado!

La sugerencia de @texttechne es mejor. En lugar de introducir una API adicional, reaccionar debe manejar múltiples elementos raíz en el renderizado.

Creo que manejar múltiples elementos raíz en el renderizado sería difícil.
Significa que hay: https://github.com/facebook/react/blob/master/src/renderers/shared/reconciler/ReactCompositeComponent.js#L1089

Tendría una matriz de elementos en lugar de un elemento.
Debido a esto, según tengo entendido, ahora tendría que crear instancias de varios elementos React: https://github.com/facebook/react/blob/master/src/renderers/shared/reconciler/ReactCompositeComponent.js# L471

Luego, monte múltiples elementos React instanciados: https://github.com/facebook/react/blob/master/src/renderers/shared/reconciler/ReactCompositeComponent.js#L471

Y conciliar todo el margen de beneficio producido en el buen orden.

Creo que viene con inconvenientes que podrían no querer eludir el proceso de reconciliación.
¿Queremos tener fragmentos como elementos o fragmentos como sintaxis de azúcar en torno a las transformaciones?

Creo que ese fragmento como elemento está bien, solo necesitaríamos crear un nuevo tipo de nodo interno similar a los nodos de texto o nodos vacíos, ¿verdad? Aunque no sé cómo los manejaríamos.

Por ejemplo, ¿cómo maneja cuando una de las raíces está desmontada? ¿Cómo manejas la actualización correctamente?
O, ¿cómo maneja múltiples raíces dentro de DevTools? (respuesta obvia: arregla las DevTools...)

Creo que un fragmento es un componente compuesto. ¿Dónde está la diferencia exactamente?
Si terminamos duplicando el código para implementar fragmentos, ¿será mejor que implementemos la sintaxis de azúcar para mantener las partes internas de React "prístinas"?

Me pregunto, he estado jugando con las partes internas de React en torno a la pregunta de Subtree (renderSubtreeIntoContainer) y siento que está algo relacionado. Cuando desee renderizar en un nuevo subárbol, tendrá que renderizar una nueva raíz, de hecho. Entonces, si admitimos múltiples raíces a nivel de árbol, ¿representamos nuevas raíces cada vez?

<p>Hi</p>
<p>There</p>

daría como resultado dos llamadas "renderizar en una nueva raíz".

En lugar de una llamada si usamos un envoltorio, ¿verdad? ¿Qué pasa con el rendimiento? ¿Sencillez? Para ser honesto, mi sentimiento es: no deberíamos tocar los internos de React para manejar esta situación. Más bien, ¿podemos sacar esta hazaña con JSX? ¿Podemos mejorar la sintaxis JSX?

(_Descargo de responsabilidad_: no estoy totalmente acostumbrado a las partes internas de React, y puede haber algunas partes que no entiendo completamente o que no entendí. Mis disculpas por el malentendido).

Editar: arreglar/aclarar cosas. Además, GitHub diseña misteriosamente los correos electrónicos de manera extraña, por lo que tuve que reformatear el bloque de código... :-(

Hola, colaborador/compromiso principal de Mithril aquí.

TL; DR: los fragmentos son extremadamente difíciles, incluso cuando la API y los componentes internos son
sencillo.

Por cierto, sé por experiencia que es _muy_ difícil de implementar. Esta
también se ha solicitado varias veces para Mithril, pero se rechazó debido a
la pura dificultad. Cada intento de implementarlo ha fallado con al menos
falla al menos un tercio del conjunto de pruebas.

Todavía estoy trabajando en los detalles de una biblioteca vdom que planeo escribir,
y tratará todo como un fragmento, pero esto es algo que tienes
literalmente (re)escribir la parte de renderizado desde cero. como reaccionar,
se desacoplará del DOM, pero la API diferirá significativamente
conceptualmente para la representación.

Aquí está el truco con los fragmentos: tienes que gestionarlos por completo
internamente o no los diferencia correctamente. Incluso
document.createContextualFragment es inútil. Solo como ejemplo, vamos
transformar dos árboles, representación omitida:

// Before
A {}
fragment {
  B[class="foo"] {}
  B[class="bar"] {}
}
C {}
D {}

// After
A {}
B[class="foo"] {}
fragment {
  C {}
}
D {}

La transformación correcta para esto debería ser reemplazar los elementos B y el elemento C , dejando el resto intacto. Descubrir eso no es trivial, y básicamente tienes que iterar a los hijos del fragmento mientras ignoras el hecho de que están en un fragmento.

Pero cuando el fragmento desaparece, tienes que manejar la semántica del gancho, como
shouldComponentUpdate (no recuerdo el nombre de React para ese gancho). Entonces
todavía tiene que rastrear los fragmentos de forma independiente. usted diferencia su
contenidos como si fueran parte de su fragmento principal, pero todavía tiene
para realizar un seguimiento de la posición de ese fragmento por el bien del componente.

O en otras palabras, los componentes ya no están intrínsecamente vinculados a sus
nodo DOM. En cambio, están vinculados al fragmento correspondiente. React, como la mayoría de las demás bibliotecas y marcos de vdom, acopla intrínsecamente el componente a su representación de árbol, incluso con los tipos esperados. Esta es la forma más fácil de implementar un algoritmo diff que
maneja los componentes. Cuando están desacoplados, hay que hacerlo por separado
contabilidad de ambos. No inicializa los componentes cuando inicializa
el nodo Ahora son dos procesos completamente separados. es dificil de hacer
inicialmente, y aún más difícil agregar soporte para después.

Gracias a todos por las palabras. Sabemos que esto es difícil y todavía lo tenemos en nuestra lista de tareas pendientes. (Preguntar con entusiasmo no hará que suceda antes @janryWang).

@isiahmeadows FYI, la rama de reescritura de Mithril admite fragmentos.

@spicyj Le invitamos a echar un vistazo a la implementación [1] [2] y las pruebas [1] [2] si aún no lo está siguiendo. Todo el motor diferencial tiene solo alrededor de 400 LOC, por lo que debería ser fácil de seguir.

@isiahmeadows Creo que GitHub se comió parte de tu comentario. El bloque de código está roto y no puedo ver pasado la primera instancia de <D /> .

Sin embargo, se ve bien en el correo electrónico. ¿Quizás encontraste un error en GitHub?

Desafortunadamente, el manejo de rebajas de GitHub se comporta de manera diferente cuando un comentario proviene de un correo electrónico. Edité el comentario para eliminar una línea en blanco y ahora aparece.

Reenvié el correo electrónico original a support@github. Con suerte, pueden arreglar el analizador. 😃

@lhorie ¿Usas la sintaxis de matriz para el fragmento?
¿Tienes polyfill para DocumentFragment?

¿Y usar un elemento contenedor "pseudo", como un comentario HTML, no es una opción? Pensé que esa era la forma en que los nodos de texto se "resolvieron" ...

Gracias por arreglar ese comentario @spicyj

Para abordar las inquietudes que planteó @isiahmeadows en su ejemplo: el nuevo motor de Mithril _no_ sigue la semántica que sugirió @isiahmeadows por varias razones:

  • implementar esa semántica haría que la diferenciación fuera _significativamente_ más compleja
  • dificultaría razonar sobre las claves y los errores relacionados con las claves, ya que es posible que los espacios clave se desangren de los componentes e incluso en los componentes hermanos y secundarios.
  • haría que los ciclos de vida de los fragmentos no fueran intuitivos (por ejemplo, en ese ejemplo, se elimina B.bar , pero también se elimina el fragmento, y se crea un nuevo fragmento para envolver C). Esto viola el principio general de que los ciclos de vida "están en cascada", lo que significa que ya no puede estar seguro de que se elimine un nodo secundario si se elimina un nodo principal determinado. Al igual que el punto anterior, esto tiene el potencial de causar fugas en las capacidades de encapsulación de un componente.
  • si, hipotéticamente, uno se encuentra con problemas de diferencias relacionados con un motor de diferencias que no se adhiere a esa semántica, la solución del espacio de aplicación es tan trivial como envolver un fragmento alrededor del nodo infractor.

Me interesaría si el equipo central pudiera ampliar la nota en la parte superior re: _por qué_ esto es difícil con la arquitectura actual. Al ver que el motor de renderizado de React y Mithril están tratando fundamentalmente de resolver los mismos problemas, y que Mithril ahora admite fragmentos en un grado que creo que es factible y útil, tal vez implementarlo en React podría ser más factible si diferentes aspectos de la semántica se evalúan por separado (y potencialmente se rechazan) como se hizo con Mithril.

Tenga en cuenta que arreglé mi comentario. Cometí algunos errores, y GitHub no hace bien el estilo de las respuestas de correo electrónico... :con el ceño fruncido:

@Primajin También me he preguntado eso, pero sospecho que se pasarían como un elemento. Es importante hacer que los fragmentos sean componibles (ver mi ejemplo arriba ). Sin embargo, es probable que haya momentos en los que desee tratarlos como una unidad también.

Tal vez, React.Children.map debería expandir los fragmentos. Si desea iterar sobre cada elemento secundario (incluidos los elementos secundarios de los fragmentos secundarios), use Children.map . Si desea tratar los fragmentos como un cuadro opaco, trabaje directamente con props.children como {matriz, elemento}.

@lhorie Sin embargo , no he estado tan involucrado en la reescritura, así que no estoy tan familiarizado con sus complejidades. He estado ocupado con el hecho de que tengo un examen final esta semana y tres la semana que viene, además estoy trabajando con alguien para organizar una pasantía que requiere mi universidad. También me he centrado en terminar Techtonic, que _casi_ tengo el CLI hecho (se rompe una prueba que no debería).

@isiahmeadows Solo un recordatorio amistoso para permanecer en el tema. Siéntase libre de usar la sala de mithril gitter si desea conversar sobre otros temas.

@aplicacionesparaartistas

Tal vez, React.Children.map debería expandir fragmentos

Mithril estable hace algo similar internamente (es decir, aplana los subconjuntos), pero me estoy alejando de ese modelo debido a razones de rendimiento (y también debido a algunos dolores de cabeza históricos con respecto a las listas de vnodos que mezclan nodos con y sin clave). Podría ser algo a considerar.

¿Y usar un elemento contenedor "pseudo", como un comentario HTML, no es una opción? Pensé que esa era la forma en que los nodos de texto se "resolvieron" ...

Hemos estado usando https://github.com/mwiencek/react-packages en producción durante algunos meses. Utiliza este enfoque de envoltura de comentarios, por lo que los fragmentos se pueden anidar sin ambigüedades.

@mwiencek ¿ Es posible usar su enfoque sin un paquete de reacción personalizado?

@mwiencek , ¿son necesarios los envoltorios de comentarios? No esperaría cosas inteligentes de los fragmentos, si mueve un elemento de un fragmento a un fragmento hermano o al elemento raíz, simplemente se puede recrear.

Entonces, si sigue el árbol vdom en orden, no necesita comentarios, ¿o sí?

De todos modos, su solución parece ser exactamente lo que se necesita para resolver este problema, a primera vista. 👍

No estrictamente, pero simplificaron la implementación en este caso.

Entonces, ¿esencialmente actualmente no es posible crear listas de descripción adecuadas <dl> con React?

<dl>
  <dt>Def 1</dt>
  <dd>Some description</dd>
  <dt>Def 2</dt>
  <dd>Some other description</dd>
</dl>

@KaiStapel Este problema se trata de devolver múltiples componentes (o elementos, supongo) de render() . Siempre que su función render solo devuelva un elemento / componente raíz, debería funcionar.

OK:

render() {
  return (
    <dl>
      <dt>Def 1</dt>
      <dd>Some description</dd>
      <dt>Def 2</dt>
      <dd>Some other description</dd>
    </dl>
  )
}

No está bien:

render() {
  return (
    <h2>my list</h2>
    <dl>
      <dt>Def 1</dt>
      <dd>Some description</dd>
      <dt>Def 2</dt>
      <dd>Some other description</dd>
    </dl>
  )
}

@GGAlanSmithee Bien codificado, sí, pero no puedes hacer:

<dl>
   loop here and print out dt/dd pairs
</dl>

Lo cual es muy triste. Lo mismo ocurre con las tablas con intervalos de filas, ya que no puede representar dos elementos <tr> a la vez :(

Desde la parte superior:

"Yo también" y "+1" no son valiosos, ni son casos de uso que ya se hayan escrito en los comentarios (por ejemplo, sabemos que no puede poner elementos <tr> o <dd> con un <div>) .

Dado que hay una solución que funciona en https://github.com/mwiencek/react-packages , ¿hay alguna posibilidad de que esto sea parte de React pronto? ¿O estamos esperando al nuevo reconciliador?

Dado que hay una solución funcional en https://github.com/mwiencek/react-packages

¿Lo está utilizando con éxito en proyectos reales?

@mwiencek

La implementación no es realmente bonita, pero si funciona para las personas, puedo enviar un PR y dejar que los desarrolladores de React lo destrocen.

Claro, por favor envíe un PR!

Acerca de enviar un PR, lo último que escuché de @spicyj fue que querían terminar el nuevo algoritmo central y hacer una solución adecuada con eso, ya que los nodos de comentarios realmente no tienen sentido en React Native. No he estado siguiendo el estado de eso, pero no creo que esos planes hayan cambiado. Mientras tanto, me alegra que la gente encuentre útiles los paquetes.

El nuevo algoritmo está en proceso y admite fragmentos. Sin embargo, no esperaría que esté listo para la producción en los próximos meses. Me pregunto si agregar esto primero a React DOM y luego a React Native es demasiado malo. La desventaja es que fragmenta un poco el ecosistema (¡juego de palabras!), pero puede darnos algo de tiempo para experimentar con esa función. Tenemos una reunión de equipo hoy, así que plantearé esta pregunta si tenemos tiempo para lograr una mejor comprensión.

@gaearon ¿Puedo señalar que admitir fragmentos es súper simple, es solo azúcar, actualmente estoy usando <frag> a modo de un pequeño envoltorio trivial? ¿Es realmente tan importante devolver varios elementos secundarios como la raíz del componente?

@syranide Estoy usando la compilación personalizada con frag en el entorno beta, sin embargo, me gustaría usar la compilación oficial de React en su lugar. ¿Puede proporcionar su envoltorio <frag> ? :) Gracias

@amertak

import React from 'react';
import createFragment from 'react-addons-create-fragment';

let nativeCreateElement = React.createElement;

React.createElement = function() {
  if (arguments[0] !== 'frag') {
    return nativeCreateElement.apply(this, arguments);
  }

  let length = arguments.length;
  if (length <= 2) {
    return null;
  }

  let children = {};
  for (let i = 2; i < length; i++) {
    children['~' + (i - 2)] = arguments[i];
  }

  return createFragment(children);
};

Hablamos más sobre esto en la última reunión del equipo. El consenso es que no queremos ir con esta implementación en particular. Sin embargo, esta característica será compatible con la reescritura del núcleo a largo plazo (no hay una línea de tiempo en esto por ahora).

También lo consideraremos nuevamente como una de las cosas en las que podríamos trabajar potencialmente para la segunda mitad de este año si la reescritura lleva demasiado tiempo o no funciona. No hay garantías de que aparezca en la lista, pero los mantendremos informados si surge.

Para tener una mejor idea de en qué trabajamos, consulte nuestro repositorio de notas de reuniones. Puede encontrar nuestra última discusión sobre esto en https://github.com/reactjs/core-notes/blob/master/2016-07/july-07.md.

@gaearon Sería interesante con tracción tener al menos una sintaxis de fragmentación oficial.

@syranide Gracias por el código, pero desafortunadamente parece que no puedo usarlo porque necesito el frag como el componente raíz de la aplicación que está siendo representado por el método ReactDOM.render y este método no aceptará el fragmento .

Gracias de todos modos, será útil para otras personas que no necesitan el frag como raíz de la aplicación.

@amertak Sí, es solo para habilitar una sintaxis más razonable para crear fragmentos, no agrega ninguna característica nueva.

@syranide
Estaba pensando si sería posible hacer comentarios manualmente y tratarlos como otro componente (que podría no ser necesario).
Los comentarios internos se manejan como #comment , por lo que tal vez pueda llamar
React.createComponent('#comment', { ... }, children) ?
Solo una idea. Pequeña solución.

La clave que falta aquí es poder renderizar el nodo comment , ¿verdad? :)

@gaearon Un poco triste porque esto no llegará pronto, pero agradezco la transparencia. ¡Buena redacción!

¿Una solución alternativa hasta una actualización?
Para mí, necesito mostrar un menú desplegable de Botstraap

render(){
    return (
        <ButtonNotification/>
        <ul className="dropdown-menu">
            {this.state.items.map(this.addItem)}
        </ul>
    );
}
ReactDOM.render(
    React.createElement(NotificationHandler, null),
    document.getElementById("listNotification")
);

Pero no es posible, una idea ?
Gracias,

http://getbootstrap.com/components/#btn-dropdowns-single

Está claramente envuelto en un solo <div class="btn-group"> como se muestra en los Documentos

Sí, por supuesto, pero hay dos elementos envueltos en <div class="btn-group"> .

render(){
    return (
        <ButtonNotification/> //ELEMENT 1
        <ul className="dropdown-menu"> //ELEMENT 2
            {this.state.items.map(this.addItem)}
        </ul>
    );
}
ReactDOM.render(
    React.createElement(NotificationHandler, null),
    document.getElementById("listNotification") //is DIV#listNotification
);
<div id="listNotification" class="btn-group"><!--wrap-->
    <a href="#">button notification</a> <!--ELEMENT1-->
    <ul> <!--ELEMENT2-->
        <li></li>
        <li></li>
    </ul>
</div>

Y dos elementos envueltos en un solo elemento no son posibles,
Gracias por tu tiempo @Primajin

Simplemente cambie todo un nivel:

render(){
    return (
        <div className="btn-group"> //WRAP
            <ButtonNotification/> //ELEMENT 1
            <ul className="dropdown-menu"> //ELEMENT 2
                {this.state.items.map(this.addItem)}
            </ul>
        </div>
    );
}
ReactDOM.render(
    React.createElement(NotificationHandler, null),
    document.getElementById("listWrapper") //or whatever your list is called
);

Está bien, pero tengo otros artículos en el padre.
Esto solo moverá el problema.

<div ...> <--!listWrapper-->
    <div class="btn-group">....</>
    <div class="btn-group">....</>
    <--!React-->
    <div class="btn-group"> //WRAP
        <ButtonNotification/> //ELEMENT 1
        <ul className="dropdown-menu"> //ELEMENT 2
            {this.state.items.map(this.addItem)}
        </ul>
    </div>
    <--!React-->
    <div class="btn-group">....</>
</div>

Y en este caso, React reemplazará todo lo contenido.
¿Es posible hacer un "agregar" sin reemplazar los otros elementos?

Gracias,

@ rifton007 así no es como funciona. Puede tener múltiples elementos/componentes como hermanos, envueltos en un contenedor. La restricción es que un componente no puede return múltiples elementos. El código que acabas de publicar funcionará.

Dicho esto, si encuentra un ejemplo que no funciona, es educado leer todo el hilo y considerar si está agregando o no un _nuevo_ ejemplo o simplemente repitiendo el mismo problema que ya se ha reconocido. Esta es una restricción conocida, y este hilo contiene una discusión extensa de los detalles y el razonamiento de la restricción. Dan también ha declarado que tienen la intención de arreglar el soporte de esto, eventualmente. ¿Qué está tratando de lograr al señalar otro ejemplo para un problema reconocido?

Lo siento, solo quería saber si alguien tendría una solución alternativa mientras tanto.
Puedes borrar mis publicaciones si es necesario.

Creo la aplicación con Framework7 y React, sin embargo, el formato html de framework7 está arreglado,

<div class="page"><div class="navbar"></div><div class="searchbar"></div><div class="page-content"></div><div class="toolbar"></div></div>

No puedo envolver los elementos secundarios de primer nivel (barra de navegación, barra de búsqueda) en otro div que no tenga la clase 'página'

Tengo un componente que devuelve una lista de filas.

para usarse en una tabla y no puedo envolverlos en una etiqueta HTML adicional (no permitido por el estándar HTML5; sé sobre tbody pero es posible que tenga varias filas devueltas por múltiples componentes secundarios que pueden necesitar combinarse en un solo tbody ). ¿Alguien ha implementado la técnica mencionada por @Prinzhorn (envolver a esos niños en un comentario HTML)? Intenté implementar un componente que representa solo el comentario HTML, pero parece que no funciona.

FYI, la reescritura en la que estamos trabajando (#6170) ya admite fragmentos. Puede seguir nuestro progreso en #7925 y en http://isfiberreadyyet.com.

El mero hecho de que el elemento <table> no pueda representar ciertos elementos es razón suficiente para agregar esta función para que sea compatible con las API web.

EDITAR: ¡Ah, fragmentos! Mirando hacia adelante a ellos.

@trusktr

Como se indica en el primer mensaje de este hilo:

Nota de los mantenedores:

Sabemos que esto es un problema y sabemos exactamente qué conjunto de problemas se puede resolver . Nosotros también queremos esto, pero es un problema difícil con nuestra arquitectura actual. Los comentarios adicionales que expresan el deseo de esta función no son útiles.

😉

Maldita sea, tengo que dejar de hacer eso.

Voté esto pero quería compartir un caso de uso válido. Supongamos que tengo 3 botones que quiero un diseño líquido CSS (izquierda, centro, derecha). El botón izquierdo siempre está visible, pero los otros dos están condicionalmente visibles. En React (específicamente React Native), estoy usando su flexbox y lo represento como:

[ Left ] { renderCenterAndRightButtons(this.state.someFlag) }

Los botones central y derecho no se colocan correctamente porque están envueltos en una Vista singular.

Sí, podría dividir los botones central y derecho en sus propios métodos, pero eso introduciría una gran cantidad de código redundante ya que comparten mucho comportamiento.

[ Left ] { renderCenterButton(this.state.someFlag) } { renderRightButton(this.state.someFlag) }

Como dice arriba, ya conocemos los casos de uso de esta función y estamos trabajando arduamente para admitirla. (Ya hay media docena de personas arriba denunciando el problema de flexbox). Dado que no parece que más discusión sea productiva, estoy bloqueando esto. Actualizaremos cuando tengamos noticias sobre la nueva implementación.

Creo que podemos cerrar esto.

La devolución de matrices desde los componentes es compatible desde React 16 Beta 1, que puede probar ahora .

Todavía hay algunas limitaciones (la compatibilidad con SSR no está lista), pero las estamos rastreando en el n.º 8854 y las solucionaremos antes de la versión final 16.

¡Gracias a todos por sus comentarios!

GRACIAS DAN

🍾🍾🍾

🦏

@gaearon ¡Impresionante mejora! ¿Es compatible con el nodo de texto puro?

Sí, también admite cadenas de retorno.

¿Puedo preguntar cómo se supone que funciona esto?

Esperaba que nos permitiera renderizar 2 elementos XJS adyacentes, pero si hago return ["foo", "bar"] (algo más útil;), obtengo el esperado bundle.js:66656 Warning: Each child in an array or iterator should have a unique "key" prop.

Entonces, ¿era la característica una forma de no rodear una lista real con un elemento extraño?

Entonces, ¿era la característica una forma de no rodear una lista real con un elemento extraño?

Sí, una forma de proporcionar varios elementos de un render. (Para obtener más información, consulte la publicación del problema inicial).

Si se sabe que todos los elementos de su matriz son cadenas, simplemente únalos y devuelva una sola cadena. De lo contrario, puede comer esta advertencia o averiguar qué hacer para envolverlos en elementos para que puedan codificarse para mejorar la reconciliación DOM, tal como lo habría hecho si hubiera incluido una matriz de cadenas dentro de otro elemento en JSX.

@diligiant devolviendo ['foo', 'bar'] no es relevante para este problema. Nunca pudo y aún no puede hacer return <div>{['foo','bar']}</div> Cada niño en una matriz debe tener un accesorio de 'clave', ya sea en una etiqueta jsx interna como <div> o se devuelve. Lo que puedes hacer ahora es:

return [<div key='1'>foo</div>, <span key='2'>bar</span>];

Elimina una gran limitación en reaccionar.

Por cierto, devolver ['foo', 'bar'] le da una advertencia, no un error, y para eliminar esa advertencia, puede unir fácilmente esas cadenas o, si son etiquetas jsx y no cadenas, puede agregarles una clave. Por lo tanto, no hay limitación sobre la devolución de matrices.

@JesperTreetop gracias.
@sassanh , según su ejemplo, parece que he sido demasiado "tímido" para usar las teclas "solo" para evitar un entorno (semánticamente) inútil <div> . ¿Quiere decir que debo seguir adelante y que no hay una penalización de rendimiento real? ¡Eso sí que sería una mejora REAL!

@diligiant Dudo que introduzca alguna penalización en el rendimiento, pero no necesita un div inútil circundante a menos que se trate de cadenas circundantes y, si se trata de cadenas circundantes, puede evitar la matriz y unir cadenas. Si no son cadenas, puede agregar la clave al componente. Por ejemplo, si tiene dos componentes Foo y Bar , puede devolver [<Foo key='foo'/>, <Bar key='bar'/>] y no necesita rodear ni sus componentes (como siempre) ni su matriz (gracias a esta nueva versión, necesitabas rodear la matriz antes de 16).

@sassanh genial entonces. Por supuesto, mi caso de uso fue con múltiples componentes. ¡¡Contento!! ;)

En realidad, me parece extraño que advirtamos sobre claves faltantes cuando todos los elementos son cadenas. No esperaría que lo hiciéramos. ¿Existe este comportamiento en 15 cuando las cadenas están dentro de un div? De lo contrario, deberíamos arreglarlo en 16 para cadenas de nivel superior (ya que es imposible darles claves).

@gaearon lo siento, mi ejemplo fue engañoso: quise decir componentes.

Revisé y bajo -beta.5 , React no emite una advertencia al representar una matriz con varias cadenas.

No obstante, estoy desconcertado por el requisito key al renderizar una matriz solo por el hecho de evitar un componente circundante. Lo entiendo y no es nada, pero probablemente generará toneladas de preguntas sobre SO (aunque no tengo nada mejor que ofrecer...)

Y finalmente, gracias de nuevo.

Esta advertencia es exactamente la misma que para cualquier otro uso de matrices de componentes, porque se reduce exactamente al mismo "trabajo adicional" para el reconciliador y, por lo tanto, a la misma optimización potencial al establecer key . Para mí, la sorpresa sería que las matrices de componentes se trataran de manera diferente dependiendo de esto, e imagino que eso también generaría algunas preguntas sobre el desbordamiento de pila. Sin mencionar que creo que implicaría algunos gastos generales solo para realizar un seguimiento en primer lugar.

.. y la mayoría de las veces devolveré una matriz de una función, quiero que aparezca la advertencia key . Parece que los momentos en los que no querrías la advertencia son la minoría, y React no tiene forma de saber si es apropiado no advertir.

La advertencia es necesaria porque la falta de claves puede causar problemas de corrección, no solo problemas de rendimiento. Esto se explica en muchos otros números que preguntan por qué las claves son necesarias, por lo que lo invito a buscarlas y leer esas discusiones. Estoy de acuerdo en que los documentos podrían ser más claros al respecto, y es algo que probablemente veremos la próxima vez que hagamos un sprint de cambio de documentos.

No hay diferencias conceptuales entre las matrices devueltas directamente desde el renderizado y las matrices dentro de un div. Por lo tanto, no hay ninguna razón por la que haya una advertencia clave en un caso pero no en el otro. Deben funcionar de la misma manera porque ambos se ven afectados por los mismos problemas cuando faltan las llaves.

Dicho esto, entendemos que es molesto especificar claves para contenido estático . Al igual que no especifica claves cuando escribe una estructura JSX donde los elementos secundarios se conocen estáticamente (y, por lo tanto, nunca se reordenan), sería bueno tener una forma de hacer esto con matrices.

En el futuro, podríamos resolver esto agregando soporte explícito para fragmentos en JSX con sintaxis como:

return (
  <>
    <div>child 1</div>
    <div>child 2</div>
  </>
);

Podría producir una matriz pero implícitamente asignar índices numéricos a los hijos porque en este caso sabemos que nunca podrán reordenarlos. Esta garantía dada por la expresión infantil JSX es exactamente lo que nos permite escapar sin especificar claves en el código JSX normal donde un div puede tener varios niños.

Pero aún no tenemos esta sintaxis. Así que por ahora esta es una limitación conocida.

@JesperTreetop & @zwily , @gaearon lo explicaron mucho mejor que yo ;)

Una vez que lo sepa, no es gran cosa, pero como todos queremos que React prospere, solo estaba diciendo...

@gaearon ¿Hay otro problema para la propuesta de sintaxis <> que podamos ver en lugar de seguir discutiendo sobre este problema? Busqué por ahí pero no pude encontrar uno.

@smrq +1 a la pregunta: sigo todo sobre esas limitaciones incómodas (resultado uno a uno rendrer() , claves y sintaxis o fragmentos JSX) pero el único ticket que conozco es https://github.com/ facebook/jsx/problemas/65

También supongo que las fibras solucionarán el problema con las teclas, pero parece que es un sueño incumplido.

Las llaves no son un "problema". :) Son una parte fundamental y necesaria de cualquier marco de vista que te permita crear listas dinámicas.

Consulte https://facebook.github.io/react/tutorial/tutorial.html#keys para obtener una explicación más detallada.

@spicyj en realidad es un «problema» ya que provoca gastos de energía prolongados por parte de los desarrolladores y existe una posibilidad fundamental de programar el marco de vista sin tal requisito (por ejemplo, https://github.com/dfilatov/vidom)

existe la posibilidad fundamental de programar el marco de vista sin tal requisito (por ejemplo, https://github.com/dfilatov/vidom)

Sin embargo, vidom usa claves en las colecciones. Técnicamente podría funcionar sin él, pero probablemente sería mucho más lento. React también podría funcionar técnicamente sin claves, pero sería bastante inesperado descubrir que la mitad de sus componentes tienen que actualizarse cuando elimina un solo elemento de una lista. Con llaves, solo se desmonta un elemento.

@goto-bus-stop vidom puede usar claves, pero no son necesarias y sin ellas solo los casos realmente grandes con muchas actualizaciones pueden causar problemas de rendimiento reales

así que considero esta parte como posible opcional (como, por ejemplo, shouldComponentUpdate ) que se puede usar para ajustes de rendimiento en casos individuales

@veged ejemplo de vidom luchando sin llaves .

No tiene idea de que se supone que debe reordenar los elementos, por lo que descarta las instancias en cada representación del componente raíz.

como alguien que está bastante familiarizado con el espacio virtual-dom [1]. puedo decir eso:

  1. las claves son necesarias para las actualizaciones predecibles de dom y estado entre hermanos similares.
  2. Las claves normalmente no son una optimización y, de hecho, suelen ser lo contrario.

[1] https://github.com/leeoniya/domvm

sin embargo, el problema inequívoco aquí (como lo describió @gaearon ) es un uso completamente estático de matrices y la diferencia entre matrices estáticas y fragmentos JSX estáticos.

@brigand O no tenga dudas de que el reordenamiento de los componentes de estado completo puede causar algunos problemas ;-) pero fuerza a todos los demás casos (en mi opinión, más de ellos) a luchar por esto ... parece controvertido

Las claves son importantes para reaccionar. Incluso si no parecen importar en algunos casos (por ejemplo, porque los componentes a continuación no tienen estado), no hay nada que le impida a usted o a otra persona del equipo agregar un componente con estado (o incluso una entrada DOM simple) en algún lugar unos niveles por debajo En unos cuantos meses. Para entonces, es posible que olvide que no tiene claves y, por lo tanto, los reordenamientos pueden hacer que el estado (o el valor de entrada) se asocie con un elemento incorrecto.

Es por eso que le recomendamos que especifique claves en todas partes para las listas dinámicas. No hacerlo conduce a errores muy difíciles de rastrear, y creemos que es mejor pasar diez segundos adicionales especificando la clave que diez horas depurando por qué el estado de un componente varios niveles por debajo se estropea en algún caso de esquina.

Estoy totalmente de acuerdo en que es un inconveniente especificar claves cuando se sabe que la lista es estática y nunca se reordena. Le invitamos a discutir esto en el repositorio JSX. Si no puede encontrar un problema para esto, puede crear uno nuevo allí.

Dado que este hilo tiene muchos suscriptores y la función se ha implementado, me gustaría bloquearlo para evitar enviar spam a muchas personas con notificaciones. Espero que las aclaraciones anteriores aborden sus inquietudes, pero si no es así, le invitamos a crear un nuevo problema para seguir discutiendo sobre un tema específico.

@smrq creó un problema de propuesta para la sintaxis de <> en el repositorio jsx: https://github.com/facebook/jsx/issues/84.

Acabamos de publicar soporte para una nueva exportación React.Fragment y la sintaxis asociada <> :
https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html

¿Fue útil esta página
0 / 5 - 0 calificaciones