Ik probeer iets als het volgende te doen in React JSX (waar ObjectRow een afzonderlijk onderdeel is):
<tbody>
for (var i=0; i < numrows; i++) {
<ObjectRow/>
}
</tbody>
Ik besef en begrijp waarom dit geen geldige JSX is, aangezien JSX verwijst naar functieaanroepen. Omdat ik echter uit templateland kom en nieuw ben in JSX, weet ik niet hoe ik het bovenstaande zou kunnen bereiken (een component meerdere keren toevoegen).
Antwoord 1, autoriteit 100%
Zie het alsof je alleen JavaScript-functies aanroept. U kunt geen for
-lus gebruiken waar de argumenten voor een functieaanroep zouden gaan:
return tbody(
for (var i = 0; i < numrows; i++) {
ObjectRow()
}
)
Zie hoe de functie tbody
een for
-lus als argument wordt doorgegeven, wat leidt tot een syntaxisfout.
Maar je kunt een array maken en dat dan als argument doorgeven:
var rows = [];
for (var i = 0; i < numrows; i++) {
rows.push(ObjectRow());
}
return tbody(rows);
Je kunt in principe dezelfde structuur gebruiken als je met JSX werkt:
var rows = [];
for (var i = 0; i < numrows; i++) {
// note: we are adding a key prop here to allow react to uniquely identify each
// element in this array. see: https://reactjs.org/docs/lists-and-keys.html
rows.push(<ObjectRow key={i} />);
}
return <tbody>{rows}</tbody>;
Overigens is mijn JavaScript-voorbeeld bijna precies waar dat voorbeeld van JSX in verandert. Speel wat met Babel REPLom een idee te krijgen hoe JSX werkt.
Antwoord 2, autoriteit 66%
Ik weet niet zeker of dit voor jouw situatie werkt, maar vaak kaartis een goed antwoord.
Als dit jouw code was met de forlus:
<tbody>
for (var i=0; i < objects.length; i++) {
<ObjectRow obj={objects[i]} key={i}>
}
</tbody>
Je zou het zo kunnen schrijven met kaart :
<tbody>
{objects.map(function(object, i){
return <ObjectRow obj={object} key={i} />;
})}
</tbody>
ES6-syntaxis:
<tbody>
{objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
Antwoord 3, autoriteit 36%
Als je nog geen array hebt om map()
te gebruiken, zoals het antwoord van @FakeRainBrigand, en dit inline wilt plaatsen zodat de bronlay-out overeenkomt met de uitvoer die dichterbij is dan het antwoord van @SophieAlpert:
Met ES2015 (ES6) syntaxis (spread- en pijlfuncties)
http://plnkr.co/edit/mfqFWODVy8dKQQOkIEGV?p=preview
<tbody>
{[...Array(10)].map((x, i) =>
<ObjectRow key={i} />
)}
</tbody>
Re: transpileren met Babel, de waarschuwingspaginazegt dat Array.from
is vereist voor verspreiding, maar op dit moment (v5.8.23
) lijkt dat niet het geval te zijn bij het verspreiden van een daadwerkelijke Array
. Ik heb een documentatieprobleemopenstaan om dat te verduidelijken. Maar gebruik op eigen risico of polyfill.
Vanille ES5
Array.apply
<tbody>
{Array.apply(0, Array(10)).map(function (x, i) {
return <ObjectRow key={i} />;
})}
</tbody>
Inline IIFE
http://plnkr.co/edit/4kQjdTzd4w69g8Suu2hT?p=preview
<tbody>
{(function (rows, i, len) {
while (++i <= len) {
rows.push(<ObjectRow key={i} />)
}
return rows;
})([], 0, 10)}
</tbody>
Combinatie van technieken uit andere antwoorden
Houd de lay-out van de bron overeenkomend met de uitvoer, maar maak het inline-gedeelte compacter:
render: function () {
var rows = [], i = 0, len = 10;
while (++i <= len) rows.push(i);
return (
<tbody>
{rows.map(function (i) {
return <ObjectRow key={i} index={i} />;
})}
</tbody>
);
}
Met ES2015-syntaxis & Array
methoden
Met Array.prototype.fill
zou je dit kunnen doen als alternatief voor het gebruik van spread zoals hierboven geïllustreerd:
<tbody>
{Array(10).fill(1).map((el, i) =>
<ObjectRow key={i} />
)}
</tbody>
(Ik denk dat je eigenlijk elk argument voor fill()
zou kunnen weglaten, maar daar ben ik niet 100% van overtuigd.) Dank aan @FakeRainBrigand voor het corrigeren van mijn fout in een eerdere versie van de fill()
oplossing (zie revisies).
key
In alle gevallen verlicht de key
attr een waarschuwing bij de ontwikkeling, maar is niet toegankelijk voor het kind. U kunt een extra attr doorgeven als u de index beschikbaar wilt hebben in het kind. Zie Lijsten en sleutelsvoor discussie.
Antwoord 4, autoriteit 7%
Gewoon de methode mapArraygebruiken met ES6-syntaxis:
<tbody>
{items.map(item => <ObjectRow key={item.id} name={item.name} />)}
</tbody>
Vergeet de eigenschap key
niet.
5, Autoriteit 5%
Als u al gebruikt lodash
, de _.times
functie is handig.
import React, { Component } from "react";
import Select from "./Select";
import _ from "lodash";
export default class App extends Component {
render() {
return (
<div className="container">
<ol>
{_.times(3, (i) => (
<li key={i}>repeated 3 times</li>
))}
</ol>
</div>
);
}
}
Antwoord 6, autoriteit 3%
Je kunt ook buiten het retourblok uitpakken:
render: function() {
var rows = [];
for (var i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return (<tbody>{rows}</tbody>);
}
Antwoord 7, autoriteit 3%
Misschien wil je afrekenen React Templates, waarmee je JSX-stijl kunt gebruiken templates in React, met een paar instructies (zoals rt-repeat).
Uw voorbeeld, als u reactie-sjablonen zou gebruiken, zou zijn:
<tbody>
<ObjectRow rt-repeat="obj in objects"/>
</tbody>
Antwoord 8, autoriteit 3%
Er zijn meerdere manieren om dit te doen. JSX wordt uiteindelijk gecompileerd naar JavaScript, dus zolang je geldig JavaScript schrijft, zit je goed.
Mijn antwoord is bedoeld om alle prachtige manieren die hier al zijn gepresenteerd te consolideren:
Als je geen array van objecten hebt, gewoon het aantal rijen:
Binnen het blok return
een Array
maken en Array.prototype.map
gebruiken:
render() {
return (
<tbody>
{Array(numrows).fill(null).map((value, index) => (
<ObjectRow key={index}>
))}
</tbody>
);
}
Buiten het return
-blok, gebruik je gewoon een normale JavaScript for-lus:
render() {
let rows = [];
for (let i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return (
<tbody>{rows}</tbody>
);
}
Onmiddellijk aangeroepen functie-uitdrukking:
render() {
return (
<tbody>
{() => {
let rows = [];
for (let i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return rows;
}}
</tbody>
);
}
Als je een reeks objecten hebt
Binnen het return
blok, .map()
elk object naar een <ObjectRow>
component:
render() {
return (
<tbody>
{objectRows.map((row, index) => (
<ObjectRow key={index} data={row} />
))}
</tbody>
);
}
Buiten het return
-blok, gebruik je gewoon een normale JavaScript for-lus:
render() {
let rows = [];
for (let i = 0; i < objectRows.length; i++) {
rows.push(<ObjectRow key={i} data={objectRows[i]} />);
}
return (
<tbody>{rows}</tbody>
);
}
Onmiddellijk aangeroepen functie-uitdrukking:
render() {
return (
<tbody>
{(() => {
const rows = [];
for (let i = 0; i < objectRows.length; i++) {
rows.push(<ObjectRow key={i} data={objectRows[i]} />);
}
return rows;
})()}
</tbody>
);
}
Antwoord 9, autoriteit 2%
Als numrowseen array is, is dat heel eenvoudig:
<tbody>
{numrows.map(item => <ObjectRow />)}
</tbody>
Het array-gegevenstype in React is veel beter. Een array kan een nieuwe array ondersteunen en filteren, verkleinen, enz. ondersteunen.
Antwoord 10, autoriteit 2%
Er zijn verschillende antwoorden die wijzen op het gebruik van de map
-instructie. Hier is een compleet voorbeeld waarbij een iterator binnen de component FeatureListwordt gebruikt om Feature-componenten weer te geven op basis van een JSON-gegevensstructuur met de naam features.
const FeatureList = ({ features, onClickFeature, onClickLikes }) => (
<div className="feature-list">
{features.map(feature =>
<Feature
key={feature.id}
{...feature}
onClickFeature={() => onClickFeature(feature.id)}
onClickLikes={() => onClickLikes(feature.id)}
/>
)}
</div>
);
Je kunt de volledige FeatureList-codeop GitHub. De features-fixture wordt hier weergegeven.
Antwoord 11, autoriteit 2%
Om een aantal keren te lussen en terug te keren, kunt u het bereiken met behulp van from
en map
:
<tbody>
{
Array.from(Array(i)).map(() => <ObjectRow />)
}
</tbody>
waar i = number of times
Als u unieke sleutel-ID’s in de gerenderde componenten wilt toewijzen, kunt u React.Children.toArray
zoals voorgesteld in de Bekijk documentatie
react.children.toarray
Retourneert de opaque data-structuur van de kinderen als een platte array met sleutels die aan elk kind zijn toegewezen. Handig als u de collecties van kinderen op uw rendermethoden wilt manipuleren, vooral als u dit wilt opnieuw ordenen of plak. Props.Children voordat u het doorgeeft.
Opmerking:
React.Children.toArray()
Wijzigt sleutels om de semantiek van geneste arrays te behouden bij het afvlakken van lijsten van kinderen. Dat wil zeggen, om elke toets in de geretourneerde array te voegen, zodat de toets van elk element wordt gescheurd naar de ingangsarray die het bevat.
<tbody>
{
React.Children.toArray(
Array.from(Array(i)).map(() => <ObjectRow />)
)
}
</tbody>
12, Autoriteit 2%
Laat ons zeggen dat we een scala aan items in uw staat hebben:
[{name: "item1", id: 1}, {name: "item2", id: 2}, {name: "item3", id: 3}]
<tbody>
{this.state.items.map((item) => {
<ObjectRow key={item.id} name={item.name} />
})}
</tbody>
Antwoord 13, autoriteit 2%
Als u ervoor kiest om dit te converteren binnen return()van de render-methode, is de eenvoudigste optie om de map( )-methode te gebruiken . Wijs uw array toe aan de JSX-syntaxis met behulp van de functie map(), zoals hieronder weergegeven (ES6-syntaxis wordt gebruikt).
In de bovenliggende component:
<tbody>
{ objectArray.map(object => <ObjectRow key={object.id} object={object.value}>) }
</tbody>
Let op: het kenmerk key
is toegevoegd aan uw onderliggende component. Als u geen sleutelkenmerk heeft opgegeven, ziet u de volgende waarschuwing op uw console.
Waarschuwing: elk kind in een array of iterator zou moeten hebben:
een unieke “sleutel” prop.
Opmerking:Een veelgemaakte fout die mensen maken, is het gebruik van index
als sleutel bij het herhalen. Het gebruik van index
van het element als sleutel is een antipatroon, en u kunt er meer over lezen hier. Kortom, als het geeneen statische lijst is, gebruik dan nooit index
als sleutel.
Nu hebt u in de component ObjectRowtoegang tot het object vanuit zijn eigenschappen.
In de ObjectRow-component
const { object } = this.props
Of
const object = this.props.object
Hiermee zou u het object moeten ophalen dat u van de bovenliggende component hebt doorgegeven aan de variabele object
in de ObjectRow-component. Nu kunt u de waarden in dat object uitspugen volgens uw doel.
Referenties:
Antwoord 14
ES2015 Array.frommet de kaartfunctie + toets
Als je niets hebt aan .map()
, kun je Array.from()
gebruiken met de functie map
om elementen te herhalen:
<tbody>
{Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>
Antwoord 15
Ik gebruik dit:
gridItems = this.state.applications.map(app =>
<ApplicationItem key={app.Id} app={app } />
);
PS: vergeet nooit de sleutel, anders krijg je veel waarschuwingen!
Antwoord 16
Een ECMAScript 2015 / Babelmogelijkheid is het gebruik van een generatorfunctie om een array van JSX:
function* jsxLoop(times, callback)
{
for(var i = 0; i < times; ++i)
yield callback(i);
}
...
<tbody>
{[...jsxLoop(numrows, i =>
<ObjectRow key={i}/>
)]}
</tbody>
Antwoord 17
…Of u kunt ook een array van objecten voorbereiden en deze toewijzen aan een functie om de gewenste uitvoer te krijgen. Ik geef hier de voorkeur aan, omdat het me helpt om de goede praktijk van codering te behouden zonder logica in de terugkeer van render.
render() {
const mapItem = [];
for(let i =0;i<item.length;i++)
mapItem.push(i);
const singleItem => (item, index) {
// item the single item in the array
// the index of the item in the array
// can implement any logic here
return (
<ObjectRow/>
)
}
return(
<tbody>{mapItem.map(singleItem)}</tbody>
)
}
Antwoord 18
Gebruik gewoon .map()
om door uw verzameling te bladeren en <ObjectRow>
items terug te sturen met rekwisieten van elke iteratie.
Ervan uitgaande dat objects
ergens een array is…
<tbody>
{ objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
Antwoord 19
Dit kan op meerdere manieren.
-
Zoals hierboven gesuggereerd, sla vóór
return
alle elementen op in de array -
Loop in
return
Methode 1
let container =[]; let arr = [1,2,3] //can be anything array, object arr.forEach((val,index)=>{ container.push(<div key={index}> val </div>) /** * 1. All loop generated elements require a key * 2. only one parent element can be placed in Array * e.g. container.push(<div key={index}> val </div> <div> this will throw error </div> ) **/ }); return ( <div> <div>any things goes here</div> <div>{container}</div> </div> )
Methode 2
return( <div> <div>any things goes here</div> <div> {(()=>{ let container =[]; let arr = [1,2,3] //can be anything array, object arr.forEach((val,index)=>{ container.push(<div key={index}> val </div>) }); return container; })()} </div> </div> )
Antwoord 20
Ik geef de voorkeur aan een benadering waarbij de programmeerlogica buiten de retourwaarde van render
valt. Dit helpt om te houden wat eigenlijk is gemaakt, gemakkelijk te grommen.
Dus ik zou waarschijnlijk zoiets doen als:
import _ from 'lodash';
...
const TableBody = ({ objects }) => {
const objectRows = objects.map(obj => <ObjectRow object={obj} />);
return <tbody>{objectRows}</tbody>;
}
Toegegeven, dit is zo’n kleine hoeveelheid code dat het inlinen prima zou kunnen werken.
Antwoord 21
Je JSX-code wordt gecompileerd tot pure JavaScript-code, alle tags worden vervangen door ReactElement
-objecten. In JavaScript kun je een functie niet meerdere keren aanroepen om de geretourneerde variabelen te verzamelen.
Het is illegaal, de enige manier is om een array te gebruiken om de door de functie geretourneerde variabelen op te slaan.
Of u kunt Array.prototype.map
die beschikbaar is sinds JavaScript ES5om deze situatie aan te pakken.
Misschien kunnen we een andere compiler schrijven om een nieuwe JSX-syntaxis te recreëren om een herhaalfunctie te implementeren, net zoals Angular’s ng-repeat
.
Antwoord 22
Je kunt natuurlijk oplossen met een .map zoals voorgesteld door het andere antwoord. Als je Babelal gebruikt, kun je overwegen om jsx-control-statements.
Ze vereisen een beetje instelling, maar ik denk dat het de moeite waard is in termen van leesbaarheid (vooral voor niet-React-ontwikkelaars).
Als u een linter gebruikt, is er ook eslint-plugin-jsx-control- verklaringen.
Antwoord 23
Hier is een eenvoudige oplossing voor.
var Object_rows = [];
for (var i = 0; i < numrows; i++) {
Object_rows.push(<ObjectRow />);
}
<tbody>{Object_rows}</tbody>;
Er is geen toewijzing en complexe code vereist. Je hoeft alleen maar de rijen naar de array te pushen en de waarden terug te geven om deze weer te geven.
Antwoord 24
U kunt ook een zelfoproepende functie gebruiken:
return <tbody>
{(() => {
let row = []
for (var i = 0; i < numrows; i++) {
row.push(<ObjectRow key={i} />)
}
return row
})()}
</tbody>
Antwoord 25
Ik gebruik het als
<tbody>
{ numrows ? (
numrows.map(obj => { return <ObjectRow /> })
) : null
}
</tbody>
Antwoord 26
Aangezien u JavaScript-syntaxis in JSX-code schrijft, moet u uw JavaScript-code tussen accolades plaatsen.
row = () => {
var rows = [];
for (let i = 0; i<numrows; i++) {
rows.push(<ObjectRow/>);
}
return rows;
}
<tbody>
{this.row()}
</tbody>
Antwoord 27
Hier is een voorbeeld uit de React-documentatie, JavaScript-expressies als kinderen:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
Wat uw zaak betreft, stel ik aan om als volgt te schrijven:
function render() {
return (
<tbody>
{numrows.map((roe, index) => <ObjectRow key={index} />)}
</tbody>
);
}
Let op de -toets is erg belangrijk, omdat reageer de -toets gebruiken om gegevens in array te verschillen.
28
je kunt iets doen als:
let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
29
Met de tijd wordt de taal volwassener en struikelen we vaak op veel voorkomende problemen zoals deze. Het probleem is om een component ‘n’ tijden te gebruiken.
{[...new Array(n)].map((item, index) => <MyComponent key={index} />)}
Waar, n -Is het aantal keren dat u wilt lussen. item
WORDT ONGEWICHT EN index
ZAL ZIJN ALS Usual. Ook, eSlint ontmoedigt met behulp van een array-index als toets.
Maar u hebt het voordeel dat u de array niet eerder wilt initialiseren en het meest belangrijk bij het vermijden van de for
lus …
Om het ongemak van item als undefined te voorkomen, kunt u een _
gebruiken, zodat deze wordt genegeerd bij het steunen en geen voeringfoutgeeft, zoals
{[...new Array(n)].map((_, index) => <MyComponent key={index} />)}