¿Cómo hacer un bucle y representar elementos en React.js sin una matriz de objetos para mapear?


146

Estoy tratando de convertir un componente jQuery a React.js y una de las cosas con las que tengo dificultades es representar un número n de elementos basados ​​en un bucle for.

Entiendo que esto no es posible o recomendado y que cuando existe una matriz en el modelo, tiene mucho sentido usarla map. Eso está bien, pero ¿qué pasa cuando no tienes una matriz? En cambio, tiene un valor numérico que equivale a un número dado de elementos para representar, entonces, ¿qué debe hacer?

Aquí está mi ejemplo, quiero prefijar un elemento con un número arbitrario de etiquetas de extensión según su nivel jerárquico. Entonces, en el nivel 3, quiero 3 etiquetas de extensión antes del elemento de texto.

En javascript:

for (var i = 0; i < level; i++) {
    $el.append('<span class="indent"></span>');
}
$el.append('Some text value');

Parece que no puedo obtener esto, o algo similar para trabajar en un componente JSX React.js. En cambio, tuve que hacer lo siguiente, primero construyendo una matriz temporal a la longitud correcta y luego haciendo un bucle de la matriz.

React.js

render: function() {
  var tmp = [];
  for (var i = 0; i < this.props.level; i++) {
    tmp.push(i);
  }
  var indents = tmp.map(function (i) {
    return (
      <span className='indent'></span>
    );
  });

  return (
    ...
    {indents}
    "Some text value"
    ...
  );
}

¿Seguramente esta no puede ser la mejor o la única forma de lograrlo? ¿Qué me estoy perdiendo?



También podría hacer eso: jsfiddle.net/crl/69z2wepo/19804
caub

Respuestas:


242

Actualizado: a partir de Reaccionar> 0.16

El método de representación no necesariamente tiene que devolver un solo elemento. También se puede devolver una matriz.

var indents = [];
for (var i = 0; i < this.props.level; i++) {
  indents.push(<span className='indent' key={i}></span>);
}
return indents;

O

return this.props.level.map((item, index) => (
    <span className="indent" key={index}>
        {index}
    </span>
));

Documentos aquí explicando sobre niños JSX


ANTIGUO:

Puedes usar un bucle en su lugar

var indents = [];
for (var i = 0; i < this.props.level; i++) {
  indents.push(<span className='indent' key={i}></span>);
}
return (
   <div>
    {indents}
    "Some text value"
   </div>
);

También puedes usar .map y fancy es6

return (
   <div>
    {this.props.level.map((item, index) => (
       <span className='indent' key={index} />
    ))}
    "Some text value"
   </div>
);

Además, debe envolver el valor de retorno en un contenedor. Usé div en el ejemplo anterior

Como dicen los documentos aquí

Actualmente, en el renderizado de un componente, solo puede devolver un nodo; si tiene, digamos, una lista de divs para devolver, debe envolver sus componentes dentro de un div, span o cualquier otro componente.


1
Eso funciona, y es mucho más simple gracias. Sí, soy consciente de que debe ajustar el valor de retorno en el contenedor, ya lo estoy haciendo, solo falta en el ejemplo.
Jonathan Miles

2
agregue claves dentro del bucle. Las claves son importantes para reaccionar.
Aamir Afridi

44
Te he estado buscando toda mi vida
olleh

2
@ElgsQianChen No es posible. Tiene que estar envuelto con alguna etiqueta. Si {indents} devuelve un solo elemento dom con contenido dentro, entonces está bien
Dhiraj

2
No entiendo por qué el método de mapa se menciona en esta respuesta, ya que solo funciona para objetos Array, lo que la pregunta establece claramente que no es el caso.
flukyspore

47

Aquí hay un ejemplo más funcional con algunas características de ES6:

'use strict';

const React = require('react');

function renderArticles(articles) {
    if (articles.length > 0) {      
        return articles.map((article, index) => (
            <Article key={index} article={article} />
        ));
    }
    else return [];
}

const Article = ({article}) => {
    return ( 
        <article key={article.id}>
            <a href={article.link}>{article.title}</a>
            <p>{article.description}</p>
        </article>
    );
};

const Articles = React.createClass({
    render() {
        const articles = renderArticles(this.props.articles);

        return (
            <section>
                { articles }
            </section>
        );
    }
});

module.exports = Articles;

1
Esta parece ser la forma más 'Reacty' de hacerlo. Pase valores como accesorios a otro subcomponente. ¡Gracias!
Michael Giovanni Pumo el

¡Esto es genial! Perfecto para cuando tu render () es html pesado.
Matthew

Para hacerlo más ES6, podría usar import React from "react"yexport default Articles
jonlink

1
Esta respuesta ni siquiera intenta responder la pregunta. La pregunta era clara: cómo convertir una for loopmatriz (u objeto) mapeable para representar un número n de elementos en un componente Reaccionar sin tener una matriz de elementos. Su solución ignora por completo ese hecho y supone que se pasa una serie de artículos de accesorios.
Jonathan Miles

17

Estoy usando Object.keys(chars).map(...)para hacer un bucle en render

// chars = {a:true, b:false, ..., z:false}

render() {
    return (
       <div>
        {chars && Object.keys(chars).map(function(char, idx) {
            return <span key={idx}>{char}</span>;
        }.bind(this))}
        "Some text value"
       </div>
    );
}

Su respuesta funcionó para mí, pero solo después de que agregué chars && ...y .bind(this)al final de mi función. Tengo curiosidad por qué simplemente Object...(y así sucesivamente) no funcionó. Seguí indefinido.
m00saca

2
Esto no responde a la pregunta, dice específicamente sin una matriz de objetos para analizar y la explicación dice explícitamente que quiero convertir un bucle for en un mapa para renderizar en un componente React. Sustituiste una matriz por un objeto que no ayuda a responder la pregunta o agrega más valor.
Jonathan Miles

16

Array.from()toma un objeto iterable para convertirlo en una matriz y una función de mapa opcional. Puede crear un objeto con una .lengthpropiedad de la siguiente manera:

return Array.from({length: this.props.level}, (item, index) => 
  <span className="indent" key={index}></span>
);

Acabo de ver tu pregunta después de escucharla la semana pasada, ¡así que fue la forma más rápida de aplicar lo que aprendí! syntax.fm/show/043/…
conradj

1
Justo lo que necesitaba para representar X número de elementos, ¡gracias!
Liran H

0

Creo que esta es la forma más fácil de bucle en reaccionar js

<ul>
    {yourarray.map((item)=><li>{item}</li>)}
</ul>

2
Esto no responde la pregunta, lea la pregunta completa antes de intentar responder.
Jonathan Miles

me ayudó y me ahorró tiempo.
Ajay Malhotra
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.