vaitaka
vaitaka

Reputation: 25

How do I map over an array of objects in React and then conditionally render a component based on a previous value?

I have this scheduling view that I want to create. However I want the Date Box to only appear if it has a unique date (and then the list of times listed below) Here's the codesandbox.

I want it to look something like this.

But instead currently the date box is rendering with every iteration. I'm unable to conditionally render the date boxes based on the current and previous date. I've been trying to map over the data and access the previously iterated date and compare if they are equal or not but it's not working like I want it to. I'll show what I've tried below. It throws an error when I try to access the previous date.

Are there any suggestions on how to achieve this?

    import "./styles.css";
import React from "react";
import styled from "styled-components";
import { format, isSameDay } from "date-fns";

const Student = styled.p`
  font-size: 16px;
  font-weight: bold;
  margin: 0px 20px 0px 20px;
`;

const NameContainer = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  margin-top: 10px;
`;

const Teacher = styled.p`
  font-size: 16px;
  margin: 0px;
`;

const BottomContainer = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  padding-left: 95px;
`;

const SubjectLabel = styled.p`
  font-size: 12px;
  font-weight: bold;
  margin-right: 5px;
`;

const Subject = styled.p`
  font-size: 14px;
`;

const Difficulty = styled.p`
  font-size: 14px;
  font-weight: bold;
  color: red;
  margin-left: 10px;
`;

const Row = styled.div`
  text-decoration: none;
  cursor: pointer;
  :hover {
    background: grey;
  }
`;

const DateBox = styled.div`
  display: flex;
  width: 70px;
  height: 25px;
  background-color: pink;
  justify-content: center;
`;

const TimeBox = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: center;
  width: 70px;
  height: 25px;
  border-radius: 15px;
  border: 1px solid black;
`;

const Time = styled.p`
  font-size: 10px;
  font-weight: 600;
`;

export const schedules = [
  {
    id: "1",
    student: "Faye",
    subject: "Math",
    difficulty: "Extreme",
    dateSent: new Date("December 17, 2020"),
    to: "Mr Skip"
  },
  {
    id: "2",
    student: "Jen",
    subject: "English",
    difficulty: "Easy",
    dateSent: new Date("December 17, 2020"),
    to: "Mr Skip"
  },
  {
    id: "3",
    student: "Martin",
    subject: "Math",
    difficulty: "Easy",
    dateSent: new Date("December 13, 2020"),
    to: "Mr Skip"
  },
  {
    id: "4",
    student: "Steve",
    subject: "Geography",
    difficulty: "Hard",
    dateSent: new Date("December 13, 2020"),
    to: "Mr Skip"
  }
];

export default function App() {
  return (
    <div>
      {schedules.length > 0 &&
        schedules.map((schedule, i, arr) => {
          const previousArray = arr[i - 1];
          // console.log("this is previous array", previousArray);
          // console.log("this is previous date", previousArray.dateSent); //this returns undefined
          return (
            <Row key={schedule.id}>
                {schedule.dateSent[i-1] !== schedule.dateSent) ? 
                (
                <DateBox>{format(schedule.dateSent, 'MMM dd')}</DateBox>
                ) : (
                null
                )}
              <NameContainer>
                <TimeBox>
                  <Time>{format(schedule.dateSent, "h:mm a")}</Time>
                </TimeBox>
                <Student>{schedule.student}</Student>
                <Teacher> For: {schedule.to}</Teacher>
              </NameContainer>
              <BottomContainer>
                <SubjectLabel>Subject</SubjectLabel>
                <Subject>{schedule.subject}</Subject>
                <Difficulty>{schedule.difficulty}</Difficulty>
              </BottomContainer>
            </Row>
          );
        })}
    </div>
  );
}

Heres the codesandbox as well!

Upvotes: 1

Views: 928

Answers (1)

Shubham Periwal
Shubham Periwal

Reputation: 2248

I added a check here to check whether i>0 and date != previousDate, then show Datebox otherwise just add row

{schedules.length > 0 &&
    schedules.map((schedule, i, arr) => {
      const previousDate = arr[i - 1];
        return (
          <Row key={schedule.id}>
            { i==0 || (previousDate &&
          previousDate.dateSent.getDate() !== schedule.dateSent.getDate()) ?
                <DateBox>{format(schedule.dateSent, "MMM dd")}</DateBox> :
                 <></>
            }
            

            <NameContainer>
              <TimeBox>
                <Time>{format(schedule.dateSent, "h:mm a")}</Time>
              </TimeBox>
              <Student>{schedule.student}</Student>
              <Teacher> For: {schedule.to}</Teacher>
            </NameContainer>
            <BottomContainer>
              <SubjectLabel>Subject</SubjectLabel>
              <Subject>{schedule.subject}</Subject>
              <Difficulty>{schedule.difficulty}</Difficulty>
            </BottomContainer>
          </Row>
        );
    })}

Output is as expected

Here is the sandbox

Upvotes: 1

Related Questions