[EZ_Scheduler] - [React] localStorage를 이용한 유저별 데이터 가져오기
[React] localStorage를 이용한 유저별 데이터 가져오기
[EZ_Scheduler] - [React, Express] 일정 추가 페이지 제작(GET, POST 구현) [React, Express] 일정 추가 페이지 제작(GET, POST 구현)[EZ_Scheduler] - [React, Express] 회원가입 페이지 제작(POST 요청) [React, Express] 회원가입
juyear-coding.tistory.com
이전 개발 일지 읽어보기!
📌세부 페이지 제작(+ Modal Popup)
안녕하세요, 대학생 개발자 주이어입니다!
오늘은 일정 세부 페이지를 제작하고 세부 일정을 추가할 수 있는 Modal Popup창을 만들어보려고 합니다!
그리고 react-calendar 라이브러리를 사용해서 만들었으니 필요하신 분은 코드 한번씩 보고가세요!
✅프로젝트 목표
- Editor(일정 세부 페이지) 제작
- react-calendar 라이브러리 적용
- Modal Popup창 제작
- 임시 데이터로 테스트
ℹ️기술 스택
- 프론트엔드 : Html, Css
- 백엔드 : Node.js
- 프레임워크 : React.js, Express.js
- 데이터베이스 : MySQL
- 빌드도구 : Vite
1. 일정 세부 페이지 제작
1-1. 일정 세부 페이지 스타일링
위 사진은 대충 구상했던 세부 페이지 화면이다. (지금 내가 봐도 뭘 그릴려고 했던건지 잘 모르겠다 ㅎㅎ..)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
return (
<div className="Editor">
<HomeHeader
leftButtonText={"<"}
headerText={curScheduleId.title}
rightButtonText={"⭐"}
onClickLeft={() => nav("/Home")}
></HomeHeader>
<Calendar
className="Calendar"
onChange={setDate}
value={date}
view="week"
minDate={formatStartDate}
maxDate={formatEndDate}
tileContent={tileContent}
/>
<div className="dateDetail">
<h4 className="selectDateText">{date.toLocaleDateString()}</h4>
<hr className="Line" />
{getEventsForDate(date).map((event, index) => (
<div key={index}>
<div className="daySchedule">
<p className="userIdText">{event.userId}</p>
<p>{event.description}</p>
</div>
<hr className="Line" />
</div>
))}
</div>
<AddButton onClickButton={() => setIsPopupOpen(true)}></AddButton>
<Modal
isPopupOpen={isPopupOpen}
setIsPopupOpen={setIsPopupOpen}
scheduleId={params.id}
events={events}
setEvents={setEvents}
></Modal>
</div>
);
|
cs |
위 코드는 Editor.jsx의 렌더 부분 코드이다. 대충 일정이 있는 날짜에 빨간색 점을 찍어 일정이 있다는 것을 알려주고 그 날짜를 클릭하면 일정을 밑에 보여주는 형식으로 만들었다. 세부 일정 추가 버튼은 Home 페이지에서 사용했었던 버튼을 가져와 그대로 사용해주었다. Calendar가 사용된 부분이 있는데, 자세한 코드는 밑에서 추가로 설명하려고 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
.Calendar {
width: 320px;
margin: auto;
}
.hidden-date {
background-color: green;
}
.dateDetail {
margin-top: 30px;
}
.dateDetail > h4 {
margin: 8px 0;
}
.dot {
height: 8px;
width: 100%;
color: lightcoral;
font-size: 25px;
margin: 0;
}
.selectDateText {
text-align: center;
}
.userIdText {
background-color: rgb(105, 150, 255);
border-radius: 5px;
padding: 2px 5px 3px 5px;
display: inline-block;
margin-bottom: 0px;
}
.daySchedule {
margin-top: 12px;
}
.daySchedule > p {
margin: 4px 20px;
}
|
cs |
위 코드는 Editor.jsx의 css코드이다. 디자인보다 기능에 중점을 두고 만들고 있는 중이라 디자인에 특별하게 사용된 건 없다.
위의 사진은 일정 세부 페이지 화면이다. 위에서 설명했듯이 일정이 있는 날짜에는 빨간색 점으로 표시되며 클릭할 경우 아래에 일정 목록을 보여준다. 추후에 디자인은 조금 더 수정할 예정이다.
1-2. useParams를 이용하여 일정별 화면 띄우기
여러 일정 중에서 클릭한 일정의 데이터를 화면에 보여주기 위해서는 useParams를 이용해야 한다.
1
2
3
4
|
<Route
path="/Schedule/:id"
element={<ScheduleDetail></ScheduleDetail>}
></Route>
|
cs |
App.jsx
useParams를 이용하기 위해서는 Route 설정에서 뒤에 :id를 붙여줘야 한다.(꼭 :id일 필요는 없다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
const params = useParams();
const curScheduleId = useScheduleId(params.id);
if (!curScheduleId) {
return <div>데이터 로딩중...</div>;
}
const startDate = new Date(curScheduleId.startDate);
const endDate = new Date(curScheduleId.endDate);
let formatStartDate = startDate.toISOString().slice(0, 19).replace("T", " ");
let formatEndDate = endDate.toISOString().slice(0, 19).replace("T", " ");
formatStartDate = new Date(formatStartDate.substr(0, 10));
formatEndDate = new Date(formatEndDate.substr(0, 10));
|
cs |
그 후 다시 Editor.jsx로 돌아와 parmas.id를 이용하여 클릭한 일정의 데이터를 가져올 수 있도록 해주었다. 일정의 데이터를 반환하는 코드는 useScheduleId라는 hooks를 만들어서 사용했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import { useContext, useEffect, useState } from "react";
import { dataContext } from "../App";
import { useNavigate } from "react-router-dom";
const useScheduleId = (id) => {
const { scheduleData, loginedUserId } = useContext(dataContext);
const [curScheduleId, setCurScheduleId] = useState();
const nav = useNavigate();
const storageData = localStorage.getItem("loginedData");
loginedUserId.current = storageData;
useEffect(() => {
const currentScheduleId = scheduleData.find(
(item) =>
String(item.id) === String(id) &&
String(loginedUserId.current) === String(item.userId)
);
if (!currentScheduleId) {
window.alert("존재하지 않는 일정입니다.");
nav("/Home", { replace: true });
}
setCurScheduleId(currentScheduleId);
}, [id]);
return curScheduleId;
};
export default useScheduleId;
|
cs |
위 코드가 useScheduleId의 코드이다. 입력받은 일정의 id와 일치하는 일정의 데이터를 가져와 반환하고 있다. 추가로 그 일정이 현재 로그인한 유저의 일정인지 확인한 후 전달해주는 기능도 넣어주었다. 이렇게 하면 다른 유저의 일정을 마음대로 볼 수 없으므로 개인의 일정을 보호해줄 수 있다.
2. react-calendar 설정하기
1
|
npm install react-calendar
|
cs |
먼저 터미널에서 위와 같이 입력하여 react-calendar 라이브러리를 다운해준다.
1
|
import Calendar from "react-calendar";
|
cs |
그 다음 Calendar를 위와 같이 불러와주고 return 부분에서 <Calendar>를 해주면 바로 사용할 수 있다.
1
2
3
4
5
6
7
8
9
|
<Calendar
className="Calendar"
onChange={setDate}
value={date}
minDate={formatStartDate}
maxDate={formatEndDate}
tileContent={tileContent}
/>
|
cs |
이 프로젝트에서는 위와 같이 사용하였는데, 각 속성을 설명해보자면,
className은 Calendar 디자인을 직접 꾸미고 싶을 때 사용한다.
onChange는 선택한 날짜가 바뀌었을 때 작동할 함수를 넣어주면 된다.(주로 useState를 사용한 set함수를 넣는다.)
value는 Calendar에서 어떤 값을 선택했는지 정해주는 변수라고 생각하면 된다.(Date 타입의 변수를 넣어준다.)
minDate는 선택가능한 날짜의 시작 날짜라고 생각하면 된다. 만약에 선택 가능한 날짜를 2025년 2월 3일로 하고 싶다면 그 값을 넣어주면 된다.
maxDate는 선택가능한 날짜의 끝나는 날짜라고 생각하면 된다.
titleContent는 각 날짜에 들어갈 내용을 설정해줄 수 있는 속성인데 위와 같이 함수를 넣어주면 된다.
1
2
3
4
5
6
7
8
9
10
11
|
const tileContent = ({ date }) => {
const formattedDate = date.toLocaleDateString();
const eventsForDate = events.filter(
(event) =>
event.date === formattedDate && String(params.id) === String(event.id)
);
if (eventsForDate.length > 0) {
return <div className="dot">•</div>;
}
return null;
};
|
cs |
위 코드는 tileContent 함수의 코드이다. 프로젝트에서 사용된 기능은 일정이 있다면 빨간색 점을 찍어주는 기능이기 때문에 events 객체에 저장되어 있는 일정을 가져와 해당 날짜와 일치한다면 dot 클래스가 들어가 있는 div를 return 해주었다. 이렇게 하면 일정이 있는 날짜에 빨간색 점을 찍어줄 수 있다.
3. Modal Popup창 제작
일정 세부 페이지에서 세부 일정 추가 버튼을 클릭했을 때 새로운 창으로 이동되는 것이 아닌 화면 중앙에 팝업창 처럼 떠서 값을 입력하는 형식으로 만들고 싶었다. 이렇게 만드는 방법을 찾아보니 Modal방식을 이용하여 만든 후 postion 속성을 이용하여 화면 중앙에 배치하면 생각한대로 만들 수 있을 것 같았다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
const Modal = ({
isPopupOpen,
setIsPopupOpen,
scheduleId,
events,
setEvents,
}) => {
const storageData = localStorage.getItem("loginedData");
const [input, setInput] = useState({
des: "",
date: new Date(),
});
const handleSave = () => {
console.log(input);
setEvents((prevEvents) => [
...prevEvents,
{
id: parseInt(scheduleId),
date: "2025. 1. 24.",
description: input.des,
userId: storageData,
},
]);
setIsPopupOpen(false);
};
if (!isPopupOpen) return null;
const onChangeInput = (e) => {
let name = e.target.name;
let value = e.target.value;
if (name === "date") {
value = new Date(value);
}
if (name) {
setInput({
...input,
[name]: value,
});
}
};
return (
<div className="overlay">
<div className="popup">
<h3>일정 추가</h3>
<div className="popupFlex">
<p>일정 설명:</p>
<input
type="text"
placeholder="설명을 입력하세요."
value={input.des}
name="des"
onChange={onChangeInput}
/>
</div>
<div className="popupFlex">
<p>끝나는 날짜:</p>
<input
type="date"
placeholder="설명을 입력하세요."
value={getStringedDate(input.date)}
name="date"
onChange={onChangeInput}
/>
</div>
<div className="buttons">
<button
className="cancelButton"
onClick={() => setIsPopupOpen(false)}
>
취소
</button>
<button onClick={handleSave}>저장</button>
</div>
</div>
</div>
);
};
|
cs |
위 코드가 Modal.jsx 코드이다. 함수는 handleSave함수와 onChangeInput함수 2개가 있는데, handleSave함수는 입력한 값을 객체에 저장하는 함수이고, onChangeInput함수는 입력한 값이 변화했을 때 state변수에 저장해주는 함수이다. 그리고 렌더 부분의 코드에는 값을 입력받을 창을 만들어주었다. 팝업창을 띄우고 지우는 것은 isPopupOpen이라는 state변수를 사용하여 true일 경우 팝업창이 나오고 false일 경우 팝업창이 사라지도록 해주었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.popup {
background: white;
padding: 10px;
border-radius: 10px;
width: 300px;
text-align: center;
}
.popup > h3 {
margin: 10px 0 12px 0;
}
.popupFlex {
display: flex;
}
.popupFlex > p {
font-size: 13px;
width: 30vw;
padding-left: 10px;
text-align: left;
}
.popupFlex > input {
margin-left: 10px;
}
.buttons {
margin-top: 10px;
}
.buttons > button {
margin: 5px;
background-color: rgb(105, 150, 255);
border-radius: 5px;
cursor: pointer;
border: solid 2px rgb(105, 150, 255);
}
.cancelButton {
background-color: rgb(150, 150, 150) !important;
border: solid 2px rgb(150, 150, 150) !important;
}
|
cs |
Modal 팝업창 디자인은 위와 같이 해주었다. 핵심적인 기능은 position: fixed를 사용하여 화면에 고정해주었고, display: flex를 사용하여 화면 중앙에 오도록 정렬 해주었다.
위 사진처럼 팝업창이 화면 중앙에 잘 나오는 것을 알 수 있다.
4. 임시 데이터로 테스트 하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
const [events, setEvents] = useState([
{
id: 2,
date: "2025. 1. 23.",
description: "수학학원 보충수업",
userId: "juyear",
},
{
id: 2,
date: "2025. 1. 22.",
description: "수학학원 보충수업",
userId: "juyear",
},
{
id: 2,
date: "2025. 1. 22.",
description: "아빠 생신 가족 외식",
userId: "chicken",
},
]);
|
cs |
위와 같이 임시 세부 일정 데이터를 추가하여 테스트를 진행해보았다.
사진과 같이 일정을 추가하면 캘린더에 잘 반영이 되는 것을 알 수 있다. 빨간점도 정상적으로 생겼으며, 날짜를 클릭했을 때 추가한 일정이 밑에 잘 출력되는 것도 알 수 있다.
console.log로 출력해본 데이터에서도 입력한 세부 일정이 잘 추가된 것을 알 수 있다.
실습 마무리
오늘은 React를 사용하여 세부 일정 페이지를 만들고 추가로 Modal Popup창까지 만들어보았습니다. 이번 개발에는 특별한 어려운 점은 없었지만 react-calendar가 처음 사용해보는 라이브러리라서 사용법을 배우는데 조금 시간이 걸렸던 것 같습니다. (Modal Popup창 만드는 것도 시간이 조금 걸리긴 했지만...) 다음에는 세부 일정 데이터를 저장할 MySQL 테이블을 생성한 후 REST API를 구현하여 서버와 연동하려고 합니다. 다음 일지도 기대해주세요!
[EZ_Scheduler] - [EZ_Scheduler] 프로젝트 마무리
[EZ_Scheduler] 프로젝트 마무리
[EZ_Scheduler] - [React] 일정 세부 페이지와 Modal Popup 만들기 [React] 일정 세부 페이지와 Modal Popup 만들기[EZ_Scheduler] - [React] localStorage를 이용한 유저별 데이터 가져오기 [React] localStorage를 이용한 유저
juyear-coding.tistory.com
다음 개발 일지 읽어보기!
'[Projects] > [EZ_Scheduler]' 카테고리의 다른 글
[EZ_Scheduler] 프로젝트 마무리 (0) | 2025.03.12 |
---|---|
[React] localStorage를 이용한 유저별 데이터 가져오기 (7) | 2025.02.16 |
[React, Express] 일정 추가 페이지 제작(GET, POST 구현) (3) | 2025.02.16 |
[React, Express] 회원가입 페이지 제작(POST 요청) (5) | 2025.02.14 |
[React, Express] 서버 구현 및 데이터베이스 연결하기(REST API) (6) | 2025.02.13 |