在.map()函数内部,在第一个键前添加一个元素

4

我希望能够重新创建类似于WhatsApp / Telegram的时间线,其中消息按天分开。
在React中呈现消息时,我使用Object.key(messages).map函数。

Object.keys(this.messages).map(e => {
    return <div key={i++}>
              { this.messages[e] }

如何在昨天的最后一条消息和今天的第一条消息之间添加“今天”等内容?

例子的“message”结构是什么? - Tomasz Bubała
谢谢您的问题!只是一个普通的对象 { body: '文本', time: 'Unix 时间戳' }。 - Igniter
2个回答

1
我会将所有消息分组为单独的数组,每个数组对应一个发生的日期。为了做到这一点,创建一个对象-其键将是唯一的日期,其值为这些日期的消息。

// object similar to your 'messages' state
const messages = {
  message1: {
    body: "one day before message",
    time: 1534433188201
  },
  message2: {
    body: "newest message",
    time: 1534519588201
  },
  message3: {
    body: "2 days before newest message",
    time: 1534346788201
  },
  message4: {
    body: "also 2 days before newest message",
    time: 1534346788250
  }
};
// creating array from your object
const messagesArray = Object.keys(messages).map(m => messages[m]);
// sorting array - oldest to newest
const latestMessages = messagesArray.sort((a, b) => a.time > b.time);
// grouping by date - create an object, each key is a different date and value is an array of messages from that day
const groupedByDate = {};
latestMessages.forEach(message => {
  const date = new Date(message.time);
  const day = date.getDate();
  const month = date.getMonth();
  const year = date.getFullYear();
  // this will create 'date_17-7-2018' format as an example - you can do whatever you want/need here
  const key = `date_${day}-${month}-${year}`;
  // push message to existing key or create new array containing this message
  if(groupedByDate[key]) {
    groupedByDate[key].push(message);
  } else {
    groupedByDate[key] = [message];
  }
});
console.log(groupedByDate);

渲染部分现在似乎很容易 - 这是我处理这个问题的示例:

映射Object.keys(groupedByDate),并为每个键返回一个带有className="date-label"(示例)的divspan。 如果从此键提取的日期等于(new Date()).getDate() - 渲染“今天”,如果是(new Date()).getDate() - 1 - 渲染“昨天”,否则渲染“X天前”。 现在,在此map循环中,您还需要map over groupedByDate[key](来自当天的消息数组)并呈现消息。


1
实际上,排序和过滤等操作已经完全由我的Firebase后端处理了。我只是想简单地在消息之间添加日期。请看 https://imgur.com/GM317lI。无论如何,感谢momentjs库! - Igniter
这里的棘手之处在于,您只需要在属于不同日期的消息之间添加日期标记。同一天内的消息不应分开。因此,我们需要在当天的第一条消息之前附加一个元素。 - Igniter
1
我不会将不是消息的东西推入“messages”数组中。我会创建一个对象,每天作为键,其值将是来自这些天的消息数组。请参见更新的答案 :) 这就是它 - 不使用momentjs。但对于这样的项目,我强烈建议使用它。您的屏幕非常有帮助,可以更好地理解问题,您应该在问题中包含它 :) - Tomasz Bubała
1
那真是太棒了 - 正是我想要学习的!这是非常聪明的方法,感谢你提供完整的工作代码片段!我已经在实现你的想法的路上了!对于令人困惑的开头,我很抱歉! - Igniter

0
    Object.keys(this.messages).map(message => {
      const date = new Date();
      date.setHours(0,0,0,0);  // will set to midnight
      const today = Math.round(date.getTime() / 1000);
      const timeDifference = this.state.time - today;
      const isInRange = timeDifference >= 0 && timeDifference <=86400;
      if (isInRange && !this.state.labelAlreadyPresent) {
        this.setState({ showLabel: true, labelAlreadyPresent: true });
      } else if(!isInRange) {
         this.setState({ labelAlreadyPresent: false, showLabel: true });
      } else {
         this.setState({ showLabel: false });
      }

      return (
         <div key={message.time}>
           {this.state.showLabel && <label> Today </label>}
           { message.body }
         </div>
       );

基本上,首先获取今天的日期并将其设置为午夜。然后获取以秒为单位的Unix时间戳。之后,将时间戳与响应中收到的时间戳进行比较,如果在0到86400(相当于1天)的范围内,则显示“今天”标签。

在初始状态下,将labelAlreadyPresentshowLabel设置为false。


谢谢您的回答!这是一个非常有趣的方法!那么同时添加以前的日期呢?请参见https://imgur.com/GM317lI - Igniter
请注意,我们需要在当天的第一条消息之前添加一个元素。当天内的其他消息不应受影响,并且应该放在一个单独的块中。 - Igniter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接