繁体   English   中英

检查映射数组中的项是否共享值

[英]Checking if items within mapped array share values

我正在使用React和moment.js构建新闻源。 使用.map我正在渲染带有标题和内容的项目。 我想检查一件商品是否在同一年份和另一件商品中发布。 如果是这种情况,我想隐藏第二项标题。

请看我的小提琴

目前我的代码呈现:

2018年3月

新闻第一项

2018年3月

新闻第二项

2017年9月

新闻第三项

2017年6月

新闻第四项

由于第一项和第二项共享同一个月和一年,我想这样渲染:

2018年3月

新闻第一项

新闻第二项

2017年9月

新闻第三项

2017年6月

新闻第四项

根据这个答案,我试图找到具有重复类名的节点,但我不是那里:

let monthNodes = [...document.querySelectorAll('.months')];
let months = []

monthNodes.map(month => {
 months.push(month.className) 
})

const count = names => 
names.reduce((a, b) => 
Object.assign(a, {[b]: (a[b] || 0) + 1}), {})

const duplicates = dict => 
Object.keys(dict).filter((a) => dict[a] > 1)

console.log(count(months)) // {March_2018: 2, December_2017: 1, November_2017: 1}
console.log(duplicates(count(months))) // [ 'March_2018' ]

也许我会以错误的方式解决这个问题,首先使用.map是一个坏主意?

更新

感谢所有的好答案,很难在他们之间挑选,因为他们都运作良好。 自从他第一次提供一个有效的例子以来,我必须接受David Ibl的回答。

可以利用Array.prototype.reduce()yearmonth组织Object形式的Articles

请参阅下面的实际示例。

的jsfiddle

 // News class News extends React.Component { // State. state = { news: [ {content: 'news item one -- march 2018', date: '2018-03-02'}, {content: 'news item two -- march 2018', date: '2018-03-17'}, {content: 'news item two -- sep 2017', date: '2017-09-21'}, {content: 'news item one -- june 2017', date: '2017-06-15'} ] } // Render. render = () => ( <div> { Object.entries(this.organised()).map(([yearmonth, articles], i) => ( <div key={i}> <h3>{yearmonth}</h3> {articles.map((article, j) => ( <div key={j}> {article.content} </div> ))} </div> )) } </div> ) // Organised. organised = () => this.state.news.reduce((total, article) => { const key = moment(article.date).format('YYYY MMMM') return { ...total, [key]: total[key] && total[key].concat(article) || [article] } }, {}) } // Mount. ReactDOM.render(<News/>,document.getElementById('container')); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"></script> <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 id="container"></div> 

你可以这样做: https//jsfiddle.net/2e27jvvh/

render() {
const arr = new Array();
return( 
    <div>
    {this.state.news.map(item => {
        const yearMonth = moment(item.date).format("MMMM YYYY");
        const yearM = moment(item.date).format("MMMM_YYYY");
        if (arr.indexOf(yearMonth) < 0){
            arr.push(yearMonth);
          return (
          <div className={'months ' + yearM}>
              <h2>{yearMonth}</h2>
              <p>{item.content}</p> 
          </div>
            ) 
        } else {
            return (
          <div className={'months ' + yearM}>
              <p>{item.content}</p> 
          </div>
            ) 
        }

        }) 
    }
 </div>
)
}

也许你应该根据年份和月份对项目进行排序,以确保即使最初没有对项目进行排序也能保证正确的行为。 但这适用于您的示例。

假设数据结构如下所示:

const data = [
  {
    date: 'March 2018',
    item: {
        title: 'news item one'
    }
  },
  {
    date: 'March 2018',
    item: {
      title: 'news item two'
    }
  },
  {
    date: 'September 2017',
    item: {
      title: 'news item two'
    }
  },
  {
    date: 'June 2017',
    item: {
      title: 'news item one'
    }
  }
]

你可以使用Array.reduce

const formatted = data.reduce((obj, item) => {
  obj[item.date] = obj[item.date] ? [...obj[item.date], item] : [item]

  return obj
}, {})

示例Codepen

1)您可以定义previousYearMonth变量并在其中存储上一年和月份名称。 您可以检查当前yearMonthpreviousYearMonth是否相同并显示/隐藏相应的标记:

render() {
  return(
    <div>
      {this.state.news.map((item, index) => {

        const yearMonth = moment(item.date).format("MMMM YYYY");
        const yearM = moment(item.date).format("MMMM_YYYY");
        const previousYearMonth = index
          ? moment(this.state.news[index - 1].date).format("MMMM YYYY")
          : false;

        return(
          <div className={'months ' + yearM}>
            {
              (yearMonth !== previousYearMonth) && (<h2>{yearMonth}</h2>)
            }
            <p>{item.content}</p>
          </div>
        )
      })
      }
    </div>
  )
}

检查小提琴的叉子

2)另一种可以在constructor方法中预处理数据并以这种方式设置title属性的方法:

constructor(props) {
  super(props);
  const data = [
    {content: 'news item one', date: '2018-03-02'},
    {content: 'news item two', date: '2018-03-17'},
    {content: 'news item two', date: '2017-09-21'},
    {content: 'news item one', date: '2017-06-15'}
  ];

  data.forEach((item, index) => {
    const yearMonth = moment(item.date).format("MMMM YYYY");
    const previousYearMonth = index
      ? moment(data[index - 1].date).format("MMMM YYYY")
      : false;

    if (yearMonth !== previousYearMonth) {
      item.title = yearMonth
    }
  });

  this.state = {
    news: data
  }
}

在这种情况下,在render方法中,您只需检查title属性是否存在并显示title:

<div>
  {
    item.title && (<h2>{item.title}</h2>)
  }
  <p>{item.content}</p>
</div> 

用这种方法检查小提琴

考虑到此列表来自API,一旦数据到达,您就可以拥有类似的内容。

const monthwise = this.state.news.reduce((res, obj) => {
  const ym = moment(obj.date).format("YYYY-MM")
  res[ym] = res[ym] || []
  res[ym].push(obj);
  return res;
}, {})

this.setState({monthwise})

现在,在render ,您可以:

render() {
  return( 
    <div>
      {Object.values(this.state.monthwise).map((items, index) => {
        return(
          <div key={index}>
            <h4>{moment(items[0].date).format("YYYY MMMM")}</h4>  
            {items.map((item, key) => <div key={key}>{item.content}</div>   )}
          </div>
        ) 
      })}
    </div>
  )
}

工作jsfiddle

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM