skip to Main Content

I have an array of logs that have the following structure let’s say:

LogItems = [
    {
       description: "I am the first log";
       timestamp: "2023-02-20T20:15:43.2357511Z"
    }, 
    {
       description: "I am the fourth log";
       timestamp: "2023-02-20T21:20:43.2357511Z"
    }, 
    {
       description: "I am the second log";
       timestamp: "2023-01-20T20:10:43.2357511Z"
    },
    {
       description: "I am the third log";
       timestamp: "2023-01-20T20:10:43.2357511Z"
    }
];

Now, I want to render this data in a different react component.
I want to show this list as described below:

20 Jan 2023
    8:10:PM
         I am the second log
         I am the third log
20 Feb 2023
   8:15 PM
        I am the first log
   9:20 PM
        I am the fourth log

Should I create a new object literal from the logs array to create a nested array similar to the view I create or can I directly render this data in JSX in the desired view?
I am new to react so, any suggestions would be really helpful.

2

Answers


  1. First of all you should group you logs by day, the format shoud be like this 2023-01-20 .
    Then group your logs by time, the format should be like this 20:10.

    Your final array should be something like this:

    LogItems = [
       {
          day: "2023-01-20",
          times: [
             {
                time: "20:10",
                descriptions: [
                   "I am the third log",
                   "I am the second log"
                ]
             }
          ]
       },
       {
          day: "2023-02-20",
          times: [
             {
                time: "20:15",
                descriptions: [
                   "I am the first log"
                ]
             },
             {
                time: "21:20",
                descriptions: [
                   "I am the fourth log"
                ]
             }
          ]
       }
    ];
    

    This is the code:

      const groupedLogs = LogItems.reduce((result, log) => {
      const [date, time] = log.timestamp.split('T');
      const day = date;
      const hour = time.slice(0, 5);
      const description = log.description;
    
      const existingDay = result.find((item) => item.day === day);
      if (existingDay) {
        const existingHour = existingDay.times.find((item) => item.time === hour);
        if (existingHour) {
          existingHour.descriptions.push(description);
        } else {
          existingDay.times.push({
            time: hour,
            descriptions: [description],
          });
        }
      } else {
        result.push({
          day: day,
          times: [
            {
              time: hour,
              descriptions: [description],
            },
          ],
        });
      }
      return result;
    }, []);
    
    Login or Signup to reply.
  2. you can use reduce to group the array into an object grouped by date and time. I have used 2 helper functions to format the date and time. Since you need January first I first sorted the array by epoch

    const LogItems = [   {       description: "I am the first log",       timestamp: "2023-02-20T20:15:43.2357511Z"    },     {       description: "I am the fourth log",       timestamp: "2023-02-20T21:20:43.2357511Z"    },    {       description: "I am the second log",      timestamp: "2023-01-20T20:10:43.2357511Z"    },    {       description: "I am the third log",       timestamp: "2023-01-20T20:10:43.2357511Z"    }];
    
    // Format date
    const formattedDate = (date) => `${date.getUTCDate()} ${date.toLocaleString('default', { month: 'short',timeZone: 'UTC' })} ${date.getUTCFullYear()}`
    
    // Format time
    const formattedTime = (date) => `${date.getUTCHours() % 12 || 12}:${date.getUTCMinutes() < 10 ? '0' : ''}${date.getUTCMinutes()} ${date.getUTCHours() >= 12 ? 'PM' : 'AM'}`
    
    
    const res = LogItems
    .map(x => ({...x,timestamp:new Date(x.timestamp)}))
    .sort((a,b) => a.timestamp.getTime()-b.timestamp.getTime())
    .reduce((acc,{description, timestamp})=>{
      const fDate = formattedDate(timestamp)
      const fTime = formattedTime(timestamp)
      acc[fDate] = acc[fDate] || {}
      acc[fDate][fTime] = acc[fDate][fTime] || []
      acc[fDate][fTime].push(description)
      return acc
    },{})
    console.log(res)

    In react you can use nested map calls to do the nested rendering of the object. Object.entries is used to convert the object to an array of [key,value] pairs so that I can call map on it. Also use a unique value for the key prop and refrain from using array index. Just used for simplicity here

    const res = {
      "20 Jan 2023": {
        "8:10 PM": [
          "I am the second log",
          "I am the third log"
        ]
      },
      "20 Feb 2023": {
        "8:15 PM": [
          "I am the first log"
        ],
        "9:20 PM": [
          "I am the fourth log"
        ]
      }
    }
    
    
    const App = () => {
      return (
        <div>
          {Object.entries(res).map(([date, times]) => (
            <div key={date}>
              <h2>{date}</h2>
              {Object.entries(times).map(([time, logs]) => (
                <div key={time}>
                  <h3>{time}</h3>
                  <ul>
                    {logs.map((log, index) => (
                      <li key={index}>{log}</li>
                    ))}
                  </ul>
                </div>
              ))}
            </div>
          ))}
        </div>
      );
    };
    
    ReactDOM.render(<App />, document.querySelector('.app'));
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <div class='app'></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search