¿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?

Jonathan Miles
fuente
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.

Dhiraj
fuente
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;
Dmytro Medvid
fuente
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>
    );
}
Mathdoy
fuente
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>
);
conradj
fuente
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>
Nasar uddin
fuente
2
Esto no responde la pregunta, lea la pregunta completa antes de intentar responder.
Jonathan Miles
me ayudó y me ahorró tiempo.
Ajay Malhotra