jsx map 函数检查对象 属性 是否与前一个对象相同
jsx map function check if object property is the same as the previous object's
我有一个对象数组,如下所示:
const artists = [{
date: '1/1/2017',
name: 'Oasis'
},
{
date: '5/1/2017',
name: 'Blur'
},
{
date: '5/1/2017',
name: 'Simply Red'
},
{
date: '10/1/2017',
name: 'Ed Sheeran'
},
{
date: '10/1/2017',
name: 'Beyonce'
},
{
date: '15/1/2017',
name: 'Jay-z'
},
];
我想遍历 artists
,如果日期与前一个日期不同,我想在艺术家姓名上方显示该日期。第一位艺术家还应显示日期。
我的代码看起来像这样,希望能使我的问题更清楚。
render(){
{artists.map((artist, index) =>
{(artists[index].date !== artists[index - 1].date) && (
<p>{ artists[index].date }</p>
)}
<div className="artists" key={index}>
<p>{ artist.name }</p>
</div>
)}
}
问题出在这行代码中:
artists[index].date !== artists[index - 1].date
index
变量的值从 0
开始,因此 artists[index - 1]
将尝试获取未定义的索引 -1
处的项目,如您的错误所述.您可以通过添加一个附加条件来检查您是否在索引 0
处来解决此问题,并且仅在您不在索引 0
.
处才执行 index - 1
index === 0 || artists[index].date !== artists[index - 1].date
问题是在循环的第一次迭代中,index
是0
,所以index - 1
是-1
,显然artists[-1]
是未定义。
一个解决方案是检查当前迭代是否是第一个迭代,这在您现有的代码中将如下所示:
(index === 0 || artist.date !== artists[index - 1].date) && (
<p>{ artist.date }</p>
)
但是,您的代码不会真正按照编写的方式运行,因为在循环的某些迭代中,您希望 return 一个元素(艺术家姓名),而在其他情况下,您希望 return 二(姓名和日期)。你可以让它与 map
一起工作,但它不会很干净。
reduce
会更干净:
artists.reduce((elms, {name, date}, index) => {
if (index === 0 || date !== artists[index - 1].date) {
elms = [ ...elms, <h4 key={date}>{date}</h4> ];
}
return [ ...elms, <p key={`${date}-${name}`}>{name}</p> ];
}, [])
此代码以一个空数组 ([]
) 开头,并且在每次迭代中添加一个日期(如果它是第一次迭代或日期与前一次不同),后跟名称。
但是,我建议改为预处理您的数据,使其更接近您最终要呈现的形状。例如:
const artists = [
{ date: '1/1/2017', name: 'Oasis' },
{ date: '5/1/2017', name: 'Blur' },
{ date: '5/1/2017', name: 'Simply Red' },
{ date: '10/1/2017', name: 'Ed Sheeran' },
{ date: '10/1/2017', name: 'Beyonce' },
{ date: '15/1/2017', name: 'Jay-Z' },
];
const artistsByDate = artists.reduce((obj, {name, date}) => {
const dateArr = obj[date] || [];
dateArr.push(name);
return { ...obj, [date]: dateArr };
}, {});
console.log(artistsByDate);
.as-console-wrapper{min-height:100%}
此代码创建一个对象,其属性是日期,其值是与这些日期关联的艺术家。
在渲染之前将数据放在右边"shape"往往会使你的渲染逻辑简单很多,这也使得生成更语义化的DOM结构变得更容易:
function groupArtistsByDate(artists) {
return artists.reduce((obj, artist) => {
const dateArr = obj[artist.date] || [];
dateArr.push(artist);
return { ...obj, [artist.date]: dateArr };
}, {});
}
const ArtistsDateGroup = ({date, artists}) => (
<li>
<h4>{date}</h4>
<ul>
{artists.map(({name}) => <li key={name}>{name}</li>)}
</ul>
</li>
);
const Artists = ({artists}) => (
<ul>
{Object.entries(groupArtistsByDate(artists)).map(([date, dateArtists]) => (
<ArtistsDateGroup key={date} date={date} artists={dateArtists}/>
)}
</ul>
);
const artists = [
{ date: '1/1/2017', name: 'Oasis' },
{ date: '5/1/2017', name: 'Blur' },
{ date: '5/1/2017', name: 'Simply Red' },
{ date: '10/1/2017', name: 'Ed Sheeran' },
{ date: '10/1/2017', name: 'Beyonce' },
{ date: '15/1/2017', name: 'Jay-Z' },
];
ReactDOM.render(<Artists artists={artists}/>, document.querySelector('div'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div></div>
使用这个:
let uiItems = [], prev = '';
artists.forEach((item, i) => {
if(item.date != prev){
uiItems.push(<div key={i}> {item.date} </div>);
}
uiItems.push(<div key={item.name}> {item.name} </div>);
prev = item.date;
})
return uiItems;
检查这个例子:
const artists = [{
date: '1/1/2017',
name: 'Oasis'
},
{
date: '5/1/2017',
name: 'Blur'
},
{
date: '5/1/2017',
name: 'Simply Red'
},
{
date: '10/1/2017',
name: 'Ed Sheeran'
},
{
date: '10/1/2017',
name: 'Beyonce'
},
{
date: '15/1/2017',
name: 'Jay-z'
},
];
let prev = '';
artists.map((item,i) => {
if(item.date != prev){
console.log(item.date, item.name);
}else{
console.log(item.name);
}
prev = item.date;
})
artists[index - 1].date
这在 0 索引处未定义,因为没有任何内容可供参考。
render(){
{artists.map((artist, index) =>
{(index > 0 && artists[index].date !== artists[index - 1].date) && (
<p>{ artists[index]date }</p>
)}
<div className="artists" key={index}>
<p>{ artist.name }</p>
</div>
)}
}
我有一个对象数组,如下所示:
const artists = [{
date: '1/1/2017',
name: 'Oasis'
},
{
date: '5/1/2017',
name: 'Blur'
},
{
date: '5/1/2017',
name: 'Simply Red'
},
{
date: '10/1/2017',
name: 'Ed Sheeran'
},
{
date: '10/1/2017',
name: 'Beyonce'
},
{
date: '15/1/2017',
name: 'Jay-z'
},
];
我想遍历 artists
,如果日期与前一个日期不同,我想在艺术家姓名上方显示该日期。第一位艺术家还应显示日期。
我的代码看起来像这样,希望能使我的问题更清楚。
render(){
{artists.map((artist, index) =>
{(artists[index].date !== artists[index - 1].date) && (
<p>{ artists[index].date }</p>
)}
<div className="artists" key={index}>
<p>{ artist.name }</p>
</div>
)}
}
问题出在这行代码中:
artists[index].date !== artists[index - 1].date
index
变量的值从 0
开始,因此 artists[index - 1]
将尝试获取未定义的索引 -1
处的项目,如您的错误所述.您可以通过添加一个附加条件来检查您是否在索引 0
处来解决此问题,并且仅在您不在索引 0
.
index - 1
index === 0 || artists[index].date !== artists[index - 1].date
问题是在循环的第一次迭代中,index
是0
,所以index - 1
是-1
,显然artists[-1]
是未定义。
一个解决方案是检查当前迭代是否是第一个迭代,这在您现有的代码中将如下所示:
(index === 0 || artist.date !== artists[index - 1].date) && (
<p>{ artist.date }</p>
)
但是,您的代码不会真正按照编写的方式运行,因为在循环的某些迭代中,您希望 return 一个元素(艺术家姓名),而在其他情况下,您希望 return 二(姓名和日期)。你可以让它与 map
一起工作,但它不会很干净。
reduce
会更干净:
artists.reduce((elms, {name, date}, index) => {
if (index === 0 || date !== artists[index - 1].date) {
elms = [ ...elms, <h4 key={date}>{date}</h4> ];
}
return [ ...elms, <p key={`${date}-${name}`}>{name}</p> ];
}, [])
此代码以一个空数组 ([]
) 开头,并且在每次迭代中添加一个日期(如果它是第一次迭代或日期与前一次不同),后跟名称。
但是,我建议改为预处理您的数据,使其更接近您最终要呈现的形状。例如:
const artists = [
{ date: '1/1/2017', name: 'Oasis' },
{ date: '5/1/2017', name: 'Blur' },
{ date: '5/1/2017', name: 'Simply Red' },
{ date: '10/1/2017', name: 'Ed Sheeran' },
{ date: '10/1/2017', name: 'Beyonce' },
{ date: '15/1/2017', name: 'Jay-Z' },
];
const artistsByDate = artists.reduce((obj, {name, date}) => {
const dateArr = obj[date] || [];
dateArr.push(name);
return { ...obj, [date]: dateArr };
}, {});
console.log(artistsByDate);
.as-console-wrapper{min-height:100%}
此代码创建一个对象,其属性是日期,其值是与这些日期关联的艺术家。
在渲染之前将数据放在右边"shape"往往会使你的渲染逻辑简单很多,这也使得生成更语义化的DOM结构变得更容易:
function groupArtistsByDate(artists) {
return artists.reduce((obj, artist) => {
const dateArr = obj[artist.date] || [];
dateArr.push(artist);
return { ...obj, [artist.date]: dateArr };
}, {});
}
const ArtistsDateGroup = ({date, artists}) => (
<li>
<h4>{date}</h4>
<ul>
{artists.map(({name}) => <li key={name}>{name}</li>)}
</ul>
</li>
);
const Artists = ({artists}) => (
<ul>
{Object.entries(groupArtistsByDate(artists)).map(([date, dateArtists]) => (
<ArtistsDateGroup key={date} date={date} artists={dateArtists}/>
)}
</ul>
);
const artists = [
{ date: '1/1/2017', name: 'Oasis' },
{ date: '5/1/2017', name: 'Blur' },
{ date: '5/1/2017', name: 'Simply Red' },
{ date: '10/1/2017', name: 'Ed Sheeran' },
{ date: '10/1/2017', name: 'Beyonce' },
{ date: '15/1/2017', name: 'Jay-Z' },
];
ReactDOM.render(<Artists artists={artists}/>, document.querySelector('div'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div></div>
使用这个:
let uiItems = [], prev = '';
artists.forEach((item, i) => {
if(item.date != prev){
uiItems.push(<div key={i}> {item.date} </div>);
}
uiItems.push(<div key={item.name}> {item.name} </div>);
prev = item.date;
})
return uiItems;
检查这个例子:
const artists = [{
date: '1/1/2017',
name: 'Oasis'
},
{
date: '5/1/2017',
name: 'Blur'
},
{
date: '5/1/2017',
name: 'Simply Red'
},
{
date: '10/1/2017',
name: 'Ed Sheeran'
},
{
date: '10/1/2017',
name: 'Beyonce'
},
{
date: '15/1/2017',
name: 'Jay-z'
},
];
let prev = '';
artists.map((item,i) => {
if(item.date != prev){
console.log(item.date, item.name);
}else{
console.log(item.name);
}
prev = item.date;
})
artists[index - 1].date
这在 0 索引处未定义,因为没有任何内容可供参考。
render(){
{artists.map((artist, index) =>
{(index > 0 && artists[index].date !== artists[index - 1].date) && (
<p>{ artists[index]date }</p>
)}
<div className="artists" key={index}>
<p>{ artist.name }</p>
</div>
)}
}