이번에는 초기 기획했던 것처럼 날짜를 골라 날짜에 맞는 데이터를 서버에서 로드, 세이브할 수 있게 해보자.
달력 관련: react-calendar, moment
위 기획했던 대로 클릭시 나오는 달력과 달력의 날짜를 가져와 헤더에 부착하고 헤더를 누르면 달력이 뜨게끔 구현해보겠다.
근데 클릭하여 나오게 만드는 것보다 그냥 바로 보여주고 어떤 날에 일일 과제가 있었는지 보여주는 게 더 나을까?
일단 날짜를 보여주고, 달력을 가지기 위해 설치할 것들을 설치하자
npm i moment
npm i react-calendar
그리고 공식페이지에서 공식과 결과물을 가져오기 위해 moment를 쓴 결과는?
import "./App.css";
import React, { useState } from "react";
import Calendar from "react-calendar";
import moment from "moment";
import "react-calendar/dist/Calendar.css";
// 따로 css 하고 싶다면 파일 코드를 그대로 가져와 Styled Component 하면 된다.
function App() {
const [value, onChange] = useState(new Date());
return (
<div className="App">
<Calendar onChange={onChange} value={value} />
<div className="text-gray-500 mt-4">{moment(value).format("YYYY년 MM월 DD일")}</div>
</div>
);
}
export default App;
요로케 나온다. 나중에 css로 조작하여 이쁘게 잡아보자. 이제 헤더를 만들 차례다.
모달처럼 만들어서 헤더를 누르면 달력이 나오게끔 만들었다.
<>
<HeaderContainer onClick={modalHandler}>
<DayToYear>{moment(value).format("YYYY년 MM월 DD일")}</DayToYear>
<DayOfWeek>{moment(value).format("dddd")}</DayOfWeek>
</HeaderContainer>
<ModalContainer>
{isModalOpen && (
<ModalBackdrop onClick={modalHandler}>
<Calendar onChange={onChange} value={value} />
</ModalBackdrop>
)}
</ModalContainer>
</>
stopPropagation()
써도 안된다.. 이거 아마 달력을 따로 페이지로 나누든가 달력 버튼을 따로 만들던가 아니면 이벤트 버블링을 따로 어떻게 해결해야하는데.. 아고라스테이츠에 물어봐야겠다.
쨌든 모달로는 구현 했다..
import React, { useState } from "react";
import Calendar from "react-calendar";
import moment from "moment";
import "./Calendar.css"; // css import
import styled from "styled-components";
const HeaderContainer = styled.div`
display: flex;
justify-content: center;
flex-direction: column;
position: relative;
cursor: pointer;
border-bottom: 1px solid #0f4c75;
height: 96px;
`;
const DayToYear = styled.div`
font-size: 30px;
margin: auto;
`;
const DayOfWeek = styled.div`
font-size: 25px;
margin: auto auto 13px;
color: #bbe1fa;
`;
const ModalContainer = styled.div`
margin: auto;
position: relative;
z-index: 2;
`;
const ModalBackdrop = styled.div`
// Modal이 떴을 때의 배경을 깔아주는 CSS를 구현
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, 0.5);
`;
const Header = () => {
// 캘린더 상태값
const [value, onChange] = useState(new Date());
// 모달 노출 상태값
const [isModalOpen, setIsModalOpen] = useState(false);
const modalHandler = (e) => {
setIsModalOpen(!isModalOpen);
};
return (
<>
<HeaderContainer onClick={modalHandler}>
<DayToYear>{moment(value).format("YYYY년 MM월 DD일")}</DayToYear>
<DayOfWeek>{moment(value).format("dddd")}</DayOfWeek>
</HeaderContainer>
<ModalContainer>
{isModalOpen && (
<ModalBackdrop onClick={modalHandler}>
<Calendar onChange={onChange} value={value} />
</ModalBackdrop>
)}
</ModalContainer>
</>
);
};
export default Header;
해결했다! useEffect를 써서 value
가 변할 때마다 리렌더링돼 중첩을 피하고도 결괏값을 도출해낼 수 있었다!
...
// 모달 노출 상태값
const [isModalOpen, setIsModalOpen] = useState(false);
const modalHandler = (e) => {
setIsModalOpen(true);
};
// useEffect에 달력 값이 변하면 setIsModalOpen가 false가 되고 달력 값을 그대로 전달하게
useEffect(() => {
setIsModalOpen(false);
}, [value]);
return (
<>
<HeaderContainer onClick={modalHandler}>
<DayToYear>{moment(value).format("YYYY년 MM월 DD일")}</DayToYear>
<DayOfWeek>{moment(value).format("dddd")}</DayOfWeek>
</HeaderContainer>
<ModalContainer>
{isModalOpen && (
<ModalBackdrop>
<Calendar onChange={onChange} value={value} />
</ModalBackdrop>
)}
</ModalContainer>
</>
);
!isModalOpen
대신 true
, false
로 한가지 기능한 하게 만들었고, value
를 디펜던시로 넣어서 변할 때마다 리렌더링되게 했고, 실행되면 setIsModalOpen
이 false
가 되게 하니 됐다!
어떻게 불러오지..