我有一个对象数组,如下所示:
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>
)}
}
答案 0 :(得分:0)
问题在于这行代码:
artists[index].date !== artists[index - 1].date
index
变量的值从0
开始,因此artists[index - 1]
将尝试获取未定义的索引-1
的项目,如您的错误所示。您可以通过添加其他条件来检查是否处于索引0
,并且如果您不在索引index - 1
,则只执行0
。
index === 0 || artists[index].date !== artists[index - 1].date
答案 1 :(得分:0)
问题在于,在循环的第一次迭代中,index
为0
,因此index - 1
为-1
,显然artists[-1]
未定义。
解决方案是检查当前迭代是否是第一个,在现有代码中看起来像这样:
(index === 0 || artist.date !== artists[index - 1].date) && (
<p>{ artist.date }</p>
)
然而,您的代码将无法按照书面形式工作,因为在循环的某些迭代中,您希望返回一个元素(艺术家名称),而在其他迭代中,您希望返回两个(名称和日期)。你可以使它与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%}
此代码创建一个对象,其属性为日期,其值为与这些日期关联的艺术家。
在渲染之前将数据放在正确的“形状”中往往会使渲染逻辑变得更加简单,这也使得生成更具语义的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>
答案 2 :(得分:0)
使用此:
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;
})
答案 3 :(得分:0)
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>
)}
}