가수면

리액트만으로 달력 만들기 (공휴일 API 적용) 본문

React/React

리액트만으로 달력 만들기 (공휴일 API 적용)

니비앙 2023. 1. 6. 14:19

대가리 깨지는 줄 알았다...

import { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import styled from "styled-components"
import { __holiday } from "../../redux/modules/loginSlice";

const Calendar = () => {
// 사용할 날짜들 상수로 선언
  const today = {
    year: new Date().getFullYear(),
    month: new Date().getMonth() + 1,
    date: new Date().getDate(),
  };
  
  // 리덕스 툴킷으로 받아온 공휴일 API 가져오기
  const dispatch = useDispatch()
  const { holiday } = useSelector(state => state.loginSlice)
  
  // 사용할 요소들 useState로 선언
  const [selectedYear, setSelectedYear] = useState(today.year)
  const [selectedMonth, setSelectedMonth] = useState(today.month)
  const [selectedDate, setSelectedDate] = useState("")
  const [toggle, setToggle] = useState(false)

// 달력의 주/일을 만들기 위한 상수 선언 
  const week = ["일", "월", "화", "수", "목", "금", "토"];
  const lastDay = new Date(selectedYear, selectedMonth, 0).getDate();

//이전 달 버튼에 대한 함수
  const prevMonth = useCallback(() => {
    if (selectedMonth === 1) {
      setSelectedMonth(12);
      setSelectedYear(selectedYear - 1);
    } else {
      setSelectedMonth(selectedMonth - 1);
    }
  }, [selectedMonth]);

//다음 달 버튼에 대한 함수
  const nextMonth = useCallback(() => {
    if (selectedMonth === 12) {
      setSelectedMonth(1);
      setSelectedYear(selectedYear + 1);
    } else {
      setSelectedMonth(selectedMonth + 1);
    }
  }, [selectedMonth]);

// 주 반환 함수
  const returnWeek = useCallback(() => {
    return week.map((v, i) => <div key={i} className={v === "일" ? "weekday sunday" : (v === "토" ? "weekday saturday" : "weekday")}>{v}</div>)
  }, [])

// 일 반환 함수
  const returnDay = useCallback(() => {
    let dayArr = []
    
    // 가져온 공휴일 데이터를 달력에 적용하기 위해 가공
    let holidayMonth = holiday.filter(v => parseInt(String(v).substring(4, 6)) === selectedMonth)
    let holidayDate = holidayMonth.map(v => parseInt(String(v).substring(6, 8)))

// 공휴일을 빨간색으로 표시하기 위한 함수
    const compare = (i) => {
      for (let h = 0; h <= holidayDate.length; h++) {
        if (holidayDate[h] === i) return true
      }
    }

// 일 반환 함수 로직
    for (const today of week) {
      const day = new Date(selectedYear, selectedMonth - 1, 1).getDay();
      if (week[day] === today) {
        for (let i = 1; i <= lastDay; i++) {
          dayArr.push(
            <button key={i}
              className={new Date(selectedYear, selectedMonth - 1, i).getDay() === 0 || compare(i) ?
                "weekday sunday" :
                (new Date(selectedYear, selectedMonth - 1, i).getDay() === 6 ? "weekday saturday" : "weekday")}
              onClick={() => setSelectedDate(`${selectedYear}년 ${selectedMonth}월 ${i}일`)} >
              {i}</ button >
          )
        }
      } else {
        dayArr.push(<div key={today} className="weekday"></div>)
      }
    }
    return dayArr
  }, [selectedYear, selectedMonth, lastDay, holiday])


// 공휴일 API 가져오기
  useEffect(() => {
    dispatch(__holiday(selectedYear))
  }, [selectedYear])

  return (
    <Container>
      <StHeader>
        <h3>{`${selectedYear}년 ${selectedMonth}월`}</h3>
        <div className="buttons">
          <div>
            <button onClick={() => prevMonth()}>이전 달</button>
            <button onClick={() => nextMonth()}>다음 달</button>
          </div>
          <div>
            <button>x</button>
          </div>
        </div>
      </StHeader>
      <StWeek>{returnWeek()}</StWeek>
      <StDate>{returnDay()}</StDate>
    </Container>
  )
}

const Container = styled.section`
  width: 350px;
  height: 400px;
  padding: 20px 20px;
  border: 1px solid black;
  `

const StHeader = styled.div`
  display: flex;
  justify-content: space-between;
  .buttons {
    display: flex;
    align-items: center;
    gap: 10px;
  }
  `

const StWeek = styled.div`
  display: flex;
  .weekday {
    width: calc(350px / 7);
    text-align: center;
  }
  .saturday {
    color: blue;
  }
  .sunday {
    color: red;
  }
`

const StDate = styled.div`
  margin-top: 20px;
  button {
    border: none;
    background-color: transparent;
    cursor: pointer;
    :hover {
      border: 1px solid black;
      border-radius: 100%;
    }
    :focus {
      border: 1px solid black;
      border-radius: 100%;
      background-color: black;
      color: whitesmoke;
    }
  }
  .weekday {
    float: left;
    width: calc(350px / 7);
    height: 50px;
  }
  .saturday {
    color: blue;
  }
  .sunday {
    color: red;
  }
  `

export default Calendar

'React > React' 카테고리의 다른 글

React Sourcemap 제거 방법  (0) 2023.02.05
useContext  (0) 2023.01.14
스크롤 막기  (0) 2022.12.28
로그인 (리액트 쿠키)  (0) 2022.12.22
useRef  (0) 2022.12.21
Comments