[英]Checking if items within mapped array share values
我正在使用React和moment.js构建新闻源。 使用.map
我正在渲染带有标题和内容的项目。 我想检查一件商品是否在同一年份和另一件商品中发布。 如果是这种情况,我想隐藏第二项标题。
目前我的代码呈现:
新闻第一项
新闻第二项
新闻第三项
新闻第四项
由于第一项和第二项共享同一个月和一年,我想这样渲染:
新闻第一项
新闻第二项
新闻第三项
新闻第四项
根据这个答案,我试图找到具有重复类名的节点,但我不是那里:
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()
按year
和month
组织Object
形式的Articles
。
请参阅下面的实际示例。
// 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
}, {})
1)您可以定义previousYearMonth
变量并在其中存储上一年和月份名称。 您可以检查当前yearMonth
和previousYearMonth
是否相同并显示/隐藏相应的标记:
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>
)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.