He escrito un código para renderizar elementos repetidos en ReactJS, pero odio lo feo que es.
render: function(){
var titles = this.props.titles.map(function(title) {
return <th>{title}</th>;
});
var rows = this.props.rows.map(function(row) {
var cells = [];
for (var i in row) {
cells.push(<td>{row[i]}</td>);
}
return <tr>{cells}</tr>;
});
return (
<table className="MyClassName">
<thead>
<tr>{titles}</tr>
</thead>
<tbody>{rows}</tbody>
</table>
);
}
¿Existe una mejor manera de lograrlo?
(Me gustaría incrustar for
bucles dentro del código de la plantilla o algún enfoque similar).
javascript
reactjs
fadedbee
fuente
fuente
Respuestas:
Puede poner expresiones entre llaves. Observe en el JavaScript compilado por qué un
for
bucle nunca sería posible dentro de la sintaxis JSX; JSX equivale a llamadas a funciones y argumentos de función azucarados. Solo se permiten expresiones.(Además: recuerde agregar
key
atributos a los componentes renderizados dentro de los bucles).JSX + ES2015 :
render() { return ( <table className="MyClassName"> <thead> <tr> {this.props.titles.map(title => <th key={title}>{title}</th> )} </tr> </thead> <tbody> {this.props.rows.map((row, i) => <tr key={i}> {row.map((col, j) => <td key={j}>{col}</td> )} </tr> )} </tbody> </table> ); }
JavaScript :
render: function() { return ( React.DOM.table({className: "MyClassName"}, React.DOM.thead(null, React.DOM.tr(null, this.props.titles.map(function(title) { return React.DOM.th({key: title}, title); }) ) ), React.DOM.tbody(null, this.props.rows.map(function(row, i) { return ( React.DOM.tr({key: i}, row.map(function(col, j) { return React.DOM.td({key: j}, col); }) ) ); }) ) ) ); }
fuente
for
amap
. Como no sé cuáles son los datos en cada una de las estructuras de datos, asumí que las filas son matrices y usé el índice de la iteración parakey
. Cuando se agregan / eliminan datos de la matriz, eso provocará una nueva representación innecesaria. Debe cambiarkey
a un valor que identifique de manera única los datos y que no dependa del orden y / o tamaño de la matriz.for
bucles y similares, ni tiene una sintaxis de plantilla para bucles.for
bucle nunca sería posible.Para ampliar la respuesta de Ross Allen, aquí hay una variante un poco más limpia que usa la sintaxis de flecha ES6.
{this.props.titles.map(title => <th key={title}>{title}</th> )}
Tiene la ventaja de que la parte JSX está aislada (no
return
o;
), lo que facilita la colocación de un bucle a su alrededor.fuente
Dado
Array(3)
que creará una matriz no iterable , debe rellenarse para permitir el uso delmap
método Array. Una forma de "convertir" es destruirlo dentro de Array-brackets, lo que "obliga" a que el Array se llene conundefined
valores, al igual queArray(N).fill(undefined)
<table> { [...Array(3)].map((_, index) => <tr key={index}/>) } </table>
Otra forma sería a través de Array
fill()
:<table> { Array(3).fill(<tr/>) } </table>
El problema con el ejemplo anterior es la falta de
key
apoyo, que es imprescindible .( No se recomienda usar un iterador
index
comokey
)Nodos anidados:
const tableSize = [3,4] const Table = ( <table> <tbody> { [...Array(tableSize[0])].map((tr, trIdx) => <tr key={trIdx}> { [...Array(tableSize[1])].map((a, tdIdx, arr) => <td key={trIdx + tdIdx}> {arr.length * trIdx + tdIdx + 1} </td> )} </tr> )} </tbody> </table> ); ReactDOM.render(Table, document.querySelector('main'))
td{ border:1px solid silver; padding:1em; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <main></main>
fuente
Array.from({length: 5}, (value, index) => <tr />)
En el espíritu de la programación funcional, hagamos que nuestros componentes sean un poco más fáciles de trabajar utilizando abstracciones.
// converts components into mappable functions var mappable = function(component){ return function(x, i){ return component({key: i}, x); } } // maps on 2-dimensional arrays var map2d = function(m1, m2, xss){ return xss.map(function(xs, i, arr){ return m1(xs.map(m2), i, arr); }); } var td = mappable(React.DOM.td); var tr = mappable(React.DOM.tr); var th = mappable(React.DOM.th);
Ahora podemos definir nuestro render de esta manera:
render: function(){ return ( <table> <thead>{this.props.titles.map(th)}</thead> <tbody>{map2d(tr, td, this.props.rows)}</tbody> </table> ); }
jsbin
Una alternativa a nuestro map2d sería una función de mapa con curry, pero la gente tiende a evitar curry.
fuente
key
atributo. El uso del índice significa que agregar / eliminar elementos obligará a volver a renderizar los objetos que podrían no haber cambiado.Esta es, en mi opinión, la forma más elegante de hacerlo (con ES6). Cree una instancia de su matriz vacía con 7 índices y mapee en una línea:
Array.apply(null, Array(7)).map((i)=> <Somecomponent/> )
felicitaciones a https://php.quicoto.com/create-loop-inside-react-jsx/
fuente
Array(...Array(10)).map((v, i) => <SomeComponent />)