jsx map函数检查object属性是否与前一个对象的

时间:2017-04-05 14:31:37

标签: javascript reactjs ecmascript-6 jsx

我有一个对象数组,如下所示:

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>

    )}

}

4 个答案:

答案 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)

问题在于,在循环的第一次迭代中,index0,因此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>

    )}

}