Napisałem kod do renderowania powtarzających się elementów w ReactJS, ale nienawidzę tego, jak brzydki jest.
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>
);
}
Czy jest lepszy sposób na osiągnięcie tego?
(Chciałbym osadzić for
pętle w kodzie szablonu lub w podobnym podejściu).
javascript
reactjs
fadedbee
źródło
źródło
Odpowiedzi:
Możesz umieścić wyrażenia w nawiasach klamrowych. Zwróć uwagę w skompilowanym JavaScript, dlaczego
for
pętla nigdy nie byłaby możliwa w składni JSX; JSX to wywołania funkcji i sugerowane argumenty funkcji. Dozwolone są tylko wyrażenia.(Ponadto: pamiętaj, aby dodać
key
atrybuty do komponentów renderowanych wewnątrz pętli).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); }) ) ); }) ) ) ); }
źródło
for
Domap
. Ponieważ nie wiem, jakie dane znajdują się w każdej ze struktur danych, założyłem, że wiersze są tablicami i użyłem indeksu iteracji dlakey
. Gdy dane są dodawane / usuwane z tablicy, spowoduje to niepotrzebne ponowne renderowanie. Należy przełączyćkey
się na wartość, która jednoznacznie identyfikuje dane i która nie jest zależna od kolejności i / lub rozmiaru tablicy.for
pętli i podobnych, ani nie ma składni szablonu dla pętli.for
pętla nigdy nie byłaby możliwa.Aby rozwinąć odpowiedź Rossa Allena, oto nieco czystszy wariant wykorzystujący składnię strzałek ES6.
{this.props.titles.map(title => <th key={title}>{title}</th> )}
Ma tę zaletę, że część JSX jest izolowana (nie
return
lub;
), co ułatwia umieszczenie wokół niej pętli.źródło
Ponieważ
Array(3)
utworzy tablicę , której nie można iterować , należy ją wypełnić, aby umożliwić użyciemap
metody Array. Sposobem na „konwersję” jest zniszczenie go w nawiasach Array, co „wymusza” wypełnienie tablicyundefined
wartościami, tak samo jakArray(N).fill(undefined)
<table> { [...Array(3)].map((_, index) => <tr key={index}/>) } </table>
Innym sposobem byłoby użycie Array
fill()
:<table> { Array(3).fill(<tr/>) } </table>
Węzły zagnieżdżone:
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>
źródło
Array.from({length: 5}, (value, index) => <tr />)
W duchu programowania funkcjonalnego sprawmy, aby nasze komponenty były nieco łatwiejsze w obsłudze, używając abstrakcji.
// 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);
Teraz możemy zdefiniować nasz render w ten sposób:
render: function(){ return ( <table> <thead>{this.props.titles.map(th)}</thead> <tbody>{map2d(tr, td, this.props.rows)}</tbody> </table> ); }
jsbin
Alternatywą dla naszego map2d byłaby funkcja mapy curried, ale ludzie unikają curry.
źródło
key
atrybutu. Korzystanie z indeksu oznacza, że dodanie / usunięcie elementów wymusi ponowne renderowanie obiektów, które mogły się nie zmienić.To jest, imo, najbardziej elegancki sposób na zrobienie tego (z ES6). Utwórz instancję pustej tablicy z 7 indeksami i mapuj w jednym wierszu:
Array.apply(null, Array(7)).map((i)=> <Somecomponent/> )
Kudos to https://php.quicoto.com/create-loop-inside-react-jsx/
źródło
Array(...Array(10)).map((v, i) => <SomeComponent />)