【问题标题】:jsx map function check if object property is the same as the previous object'sjsx map函数检查对象属性是否与前一个对象的相同
【发布时间】:2017-04-05 14:31:36
【问题描述】:

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

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>

    )}

}

【问题讨论】:

  • 这是什么问题,它不起作用吗?
  • @MayankShukla 不,不工作。无法读取date of undefined
  • artists[index]date 不是有效的 JavaScript。
  • 抱歉@Jordan 这是问题中的错字
  • @RaulRodriguez 感谢您接受我的回答。在你这样做之后,我意识到我的代码和你的一样,不会像写的那样工作。我已经用工作 sn-p 中的一些替代代码更新了我的答案。

标签: javascript reactjs ecmascript-6 jsx


【解决方案1】:

问题是在循环的第一次迭代中,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】:

    问题出在这行代码中:

    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
    

    【讨论】:

      【解决方案3】:
      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>
      
          )}
      
      }

      【讨论】:

      • 这没有显示第一位艺术家的日期,我想这是我的问题
      【解决方案4】:

      使用这个:

      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;
      })

      【讨论】:

        猜你喜欢
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-27
        • 2016-06-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多