javascript - helmet - react map用法
在React JSX中循環 (20)
ES2015 Array.from與地圖功能+鍵
如果你沒有.map()
東西,你可以使用Array.from()
和mapFn
來重複元素:
<tbody>
{Array.from({ length: 5 }, (v, k) => <ObjectRow key={k} />)}
</tbody>
我正在嘗試在React JSX(其中ObjectRow是一個單獨的組件)中執行以下操作:
<tbody>
for (var i=0; i < numrows; i++) {
<ObjectRow/>
}
</tbody>
我意識到並理解為什麼這不是有效的JSX,因為JSX映射到函數調用。 但是,來自模板領域並且是JSX的新手,我不確定如何實現上述目標(多次添加組件)。
...或者,您也可以準備一個對像數組並將其映射到函數以獲得所需的輸出。 我更喜歡這個,因為它有助於我在渲染返回內部保持不帶邏輯的編碼的良好實踐。
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>
)
}
不知道這是否適合您的情況,但通常map是一個很好的答案。
如果這是你用for循環的代碼:
<tbody>
for (var i=0; i < objects.length; i++) {
<ObjectRow obj={objects[i]} key={i}>
}
</tbody>
你可以像這樣用map寫下來:
<tbody>
{objects.map(function(object, i){
return <ObjectRow obj={object} key={i} />;
})}
</tbody>
ES6語法:
<tbody>
{objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
以下是來自React文檔的示例: https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions-as-children : https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions-as-children
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>
);
}
作為你的情況,我建議你這樣寫:
function render() {
return (
<tbody>
{numrows.map((roe, index) => <ObjectRow key={index} />)}
</tbody>
);
}
請注意Key是非常重要的,因為React使用Key來區分數組中的數據。
你可以做一些事情:
let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
你可以用其他答案建議的.map解決。 如果你已經使用了babel,你可以考慮使用jsx-control-statements他們需要一些設置,但我認為這是值得的可讀性(特別是對於無反應的開發人員)。 如果你使用eslint-plugin-jsx-control-statements ,還有eslint-plugin-jsx-control-statements
使用ES6語法簡單地使用map Array方法:
<tbody>
{items.map(item => <ObjectRow key={item.id} name={item.name} />)}
</tbody>
不要忘記key
財產。
做這件事有多種方式。 JSX最終會被編譯成JavaScript,所以只要你寫了有效的JavaScript,你就會很好。
我的答案旨在鞏固已經提出的所有美妙方式:
如果你沒有一個對像數組,簡單的行數:
在return
塊中,創建一個Array
並使用Array.prototype.map
:
render() {
return (
<tbody>
{Array(numrows).fill(null).map((value, index) => (
<ObjectRow key={index}>
))}
</tbody>
);
}
在return
塊外部,只需使用普通的JavaScript for-loop:
render() {
let rows = [];
for (let i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return (
<tbody>{rows}</tbody>
);
}
立即調用函數表達式:
render() {
return (
<tbody>
{() => {
let rows = [];
for (let i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return rows;
}}
</tbody>
);
}
如果你有一個對像數組
在return
塊中,將每個對象的.map()
轉換為<ObjectRow>
組件:
render() {
return (
<tbody>
{objectRows.map((row, index) => (
<ObjectRow key={index} data={row} />
))}
</tbody>
);
}
在return
塊外部,只需使用普通的JavaScript for-loop:
render() {
let rows = [];
for (let i = 0; i < objectRows.length; i++) {
rows.push(<ObjectRow key={i} data={objectRows[i]} />);
}
return (
<tbody>{rows}</tbody>
);
}
立即調用函數表達式:
render() {
return (
<tbody>
{() => {
let rows = [];
for (let i = 0; i < objectRows.length; i++) {
rows.push(<ObjectRow key={i} data={objectRows[i]} />);
}
return rows;
}}
</tbody>
);
}
如果numrows是一個數組,並且非常簡單。
<tbody>
{numrows.map(item => <ObjectRow />)}
</tbody>
React中的數組數據類型非常好,數組可以返回新數組,並支持過濾,減少等。
如果你已經在使用lodash,那麼_.times
函數很方便。
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}>
<Select onSelect={this.onSelect}>
<option value="1">bacon</option>
<option value="2">cheez</option>
</Select>
</li>
)}
</ol>
</div>
);
}
}
如果你還沒有像@ FakeRainBrigand的答案那樣map()
的數組,並且想要內聯這個,那麼源佈局對應的輸出比@ SophieAlpert的答案更接近:
借助ES2015(ES6)語法(擴展和箭頭函數)
http://plnkr.co/edit/mfqFWODVy8dKQQOkIEGV?p=preview
<tbody>
{[...Array(10)].map((x, i) =>
<ObjectRow key={i} />
)}
</tbody>
Re:與Babel一起發布,它的警告頁面說Array.from
是傳播所必需的,但是目前( v5.8.23
),傳播實際Array
時似乎並不是這種情況。 我有一個文檔問題,以澄清這一點。 但是請自擔風險或使用polyfill。
香草ES5
Array.apply
<tbody>
{Array.apply(0, Array(10)).map(function (x, i) {
return <ObjectRow key={i} />;
})}
</tbody>
內聯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>
來自其他答案的技術組合
保持與輸出相對應的源佈局,但使內聯部分更緊湊:
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>
);
}
使用ES2015語法和Array
方法
使用Array.prototype.fill
您可以將其作為使用傳播的替代方法,如上所示:
<tbody>
{Array(10).fill(1).map((el, i) =>
<ObjectRow key={i} />
)}
</tbody>
(我認為你實際上可以省略任何參數來fill()
,但我不是100%)。感謝@FakeRainBrigand在fill()
解決方案的早期版本中糾正我的錯誤(請參閱修訂版)。
key
在所有情況下, key
attr緩解發展構建的警告,但兒童無法訪問。 如果您希望子項中可用索引,則可以傳遞額外的attr。 請參閱列表和鍵以供討論。
很好的問題。
當我想添加一定數量的組件時,我所做的就是使用輔助函數。
定義一個返回JSX的函數:
const myExample = () => {
let myArray = []
for(let i = 0; i<5;i++) {
myArray.push(<MyComponent/>)
}
return myArray
}
//... in JSX
<tbody>
{myExample()}
</tbody>
您的JSX代碼將編譯為純JavaScript代碼,任何標籤都將被ReactElement
對象替換。 在JavaScript中,您不能多次調用函數來收集其返回的變量。
這是非法的,唯一的方法是使用數組來存儲函數返回的變量。
或者你可以使用自JavaScript ES5以來可用的map來處理這種情況。
也許我們可以編寫其他編譯器來重新創建一個新的JSX語法來實現像Angular的ng-repeat
一樣的重複函數。
您需要將元素添加到數組並呈現元素數組。
這可以幫助減少重新渲染組件所需的時間。
以下是一些可能有所幫助的粗略代碼:
MyClass extends Component {
constructor() {
super(props)
this.state = { elements: [] }
}
render() {
return (<tbody>{this.state.elements}<tbody>)
}
add() {
/*
* The line below is a cheap way of adding to an array in the state.
* 1) Add <tr> to this.state.elements
* 2) Trigger a lifecycle update.
*/
this.setState({
elements: this.state.elements.concat([<tr key={elements.length}><td>Element</td></tr>])
})
}
}
我傾向於贊成編程邏輯發生在render
返回值之外的方法。 這有助於保持實際上易於理解的內容。
所以我可能會這樣做:
import _ from 'lodash';
...
const TableBody = ({ objects }) => {
const objectRows = objects.map(obj => <ObjectRow object={obj} />);
return <tbody>{objectRows}</tbody>;
}
無可否認,這是少量的內聯代碼,可能會正常工作。
我喜歡它
<tbody>
{ numrows ? (
numrows.map(obj => { return <ObjectRow /> })
) : null}
</tbody>
把它想像成你只是在調用JavaScript函數。 你不能在函數調用中放置一個for
循環:
return tbody(
for (var i = 0; i < numrows; i++) {
ObjectRow()
}
)
但是你可以創建一個數組,然後將其傳遞給:
var rows = [];
for (var i = 0; i < numrows; i++) {
rows.push(ObjectRow());
}
return tbody(rows);
使用JSX時,您可以使用基本相同的結構:
var rows = [];
for (var i = 0; i < numrows; i++) {
// note: we add 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>;
順便說一句,我的JavaScript例子幾乎就是JSX轉換成的例子。 利用Babel REPL來體驗JSX的工作方式。
有幾個答案指向使用map
語句。 下面是一個完整的示例,它使用FeatureList組件中的迭代器根據名為features的JSON數據結構列出Feature組件。
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>
);
您可以在GitHub上查看完整的FeatureList代碼 。 這裡列出了特徵夾具 。
讓我們說我們有你們國家的一系列物品:
[{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>
這可以通過多種方式完成。
- 如上所述,在
return
存儲數組中的所有元素之前 循環內
return
方法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> )
方法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> )