Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I render repeating React elements?

I've written some code to render repeating elements in ReactJS, but I hate how ugly it is.

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>   ); }  

Is there a better way to achieve this?

(I would like to embed for loops within the template code, or some similar approach.)

like image 947
fadedbee Avatar asked Sep 03 '14 14:09

fadedbee


People also ask

Can a render method return multiple elements?

render() should return single element. You can split it up and have multiple components which implement some dedicated logic which is better and used to be a good practice in React.

How do I display multiple elements in React?

In the ReactDOM. render you still can't render multiple items because react needs a root. So you can render a single component inside the ReactDOM. render and render an array of items in the internal component.


2 Answers

You can put expressions inside braces. Notice in the compiled JavaScript why a for loop would never be possible inside JSX syntax; JSX amounts to function calls and sugared function arguments. Only expressions are allowed.

(Also: Remember to add key attributes to components rendered inside loops.)

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);               })             )           );         })       )     )   ); }  
like image 84
Ross Allen Avatar answered Sep 28 '22 14:09

Ross Allen


Since Array(3) will create an un-iterable array, it must be populated to allow the usage of the map Array method. A way to "convert" is to destruct it inside Array-brackets, which "forces" the Array to be filled with undefined values, same as Array(N).fill(undefined)

<table>     { [...Array(3)].map((_, index) => <tr key={index}/>) } </table> 

Another way would be via Array fill():

<table>     { Array(3).fill(<tr/>) } </table> 

⚠️ Problem with above example is the lack of key prop, which is a must.
(Using an iterator's index as key is not recommended)


Nested Nodes:

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>
like image 24
vsync Avatar answered Sep 28 '22 13:09

vsync