어떤날 부터 오늘까지 지난 날짜를 계산하고
다른날 까지 남은 날짜를 계산하는 프로그램이다
그냥 갑자기 Date 활용하면 만들 수 있을 거 같아서 도전
Date 객체의 주요 함수를 이용하여 날짜와 시간정보를 가져와 작성할 예정이다
뼈대인 HTNL을 작성하였다 버튼은 사용자 입력값을 받을 예정이고 기념일이나
날짜부분은 아무 숫자나 임의로 값을 설정하였다 값이 바뀌어야 할 부분에 각각 id 를 붙여주었다

기능구현이 목적이라 css는 따로 설정해두지 않았다
Html ,js ,css 만으로 원하는걸 구현 할 수 있겠지만
리액트로 구현을 해보고 싶다는 생각을 하였다 (걍 나대지 말고 만들었으면 금방 끝났을텐데.....)
React에서 상태(state)를 관리하기 위해 useState를 이용해야 컴포넌트의 상태를 관리하고 동적으로 변경되는 데이터를 처리할 수 있기에 리액트로 작성한 코드는 다음과 같다

동일하게 동작하지만 의문점이 생겼다

반복하는 배열엔 map함수를 이용하여 각 배열의 정보를 동적으로 생성하게 하였고 결과는 동일 했다 useState를 통해 관리할 수 있게 되어서
리팩토링 안 했으면 기념일 추가고 뭐고 못 하지 않았을까
useState 배열에 600, 700 이렇게 수동으로 넣어 주는게 아니라
맨 아레 +버튼을 누르면 600일 700일 추가 되도록 만들어 문제를 해결하고자 한다

addNewAnniversaries이름의 함수를 만들어 아래 + 버튼에 onClick 함수를 엮어서 버튼이 누를 때 마다 이벤트가 발생하도록 하려고 한다

맨아래 붙은 초라한 +버튼
<button onClick={addNewAnniversaries}>+</button>
// 새로운 기념일을 추가하는 함수
const addNewAnniversaries = () => {
// 현재 배열의 마지막 기념일을 가져온 뒤, 100씩 증가시켜 새로운 배열을 생성
const lastAnniversary = parseInt(title[title.length - 1]); //마지막으로 추가된 기념일을 가져옵니다.
const newAnniversaries = Array.from({ length: 1 }, (_, index) => `${lastAnniversary + (index + 1) * 100}일`);
// 이전 기념일 배열과 새로운 배열을 합쳐 업데이트
setTitle([...title, ...newAnniversaries]);
}
parseInt함수를 이용하여 배열의 마지막 500일 에서 숫자 500을 추출 하여 100씩 더한값을 새로운 배열로 만들어 이전 기념일 배열과 합쳐주는 코드다 버튼 태그와 온클릭으로 엮어주니 버튼을 누를 때 마다 500이후의 배열이 추가된다
테스트영상
https://im7.ezgif.com/tmp/ezgif-7-259c2444a3.webp
기능구현 다 하지도 않았는데 힘들어죽겟다2시간반 걸린거 실화냐,,,,,,,,,,,,,,,,,,
실패를 격고 대폭 수정한 코드
import React, { useState, useEffect } from "react";
import "./App.css";
function App() {
const [anniversaries, setAnniversaries] = useState([]);
const [remainingTime, setRemainingTime] = useState([]);
const [inputTitle, setInputTitle] = useState('');
const [inputDate, setInputDate] = useState('');
const [todayDate, setTodayDate] = useState(formatDate(new Date()));
const [firstMeetDate, setFirstMeetDate] = useState('');
const [firstMeetDays, setFirstMeetDays] = useState(0);
const [showModal, setShowModal] = useState(false);
const addNewAnniversary = () => {
if (inputTitle && inputDate) {
const newAnniversaries = [...anniversaries];
newAnniversaries.push({
title: inputTitle,
date: inputDate,
});
setAnniversaries(newAnniversaries);
setRemainingTime([...remainingTime, null]);
setInputTitle('');
setInputDate('');
handleModalClose();
}
};
const setFirstMeet = (selectedDate) => {
if (selectedDate) {
setFirstMeetDate(selectedDate);
const today = new Date(todayDate).getTime();
const meetDay = new Date(selectedDate).getTime();
const gap = today - meetDay;
const days = Math.floor(gap / (1000 * 60 * 60 * 24));
setFirstMeetDays(days);
}
};
useEffect(() => {
const intervalId = setInterval(() => {
const now = new Date().getTime();
const updatedRemainingTime = anniversaries.map((anniversary) => {
const dday = new Date(anniversary.date).getTime();
const gap = dday - now;
const day = Math.floor(gap / (1000 * 60 * 60 * 24));
const hour = Math.floor((gap % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const min = Math.floor((gap % (1000 * 60 * 60)) / (1000 * 60));
const sec = Math.floor((gap % (1000 * 60)) / 1000);
return {
days: day,
hours: hour,
minutes: min,
seconds: sec,
};
});
setRemainingTime(updatedRemainingTime);
}, 1000);
return () => clearInterval(intervalId);
}, [anniversaries]);
useEffect(() => {
setFirstMeet(firstMeetDate);
}, [firstMeetDate, todayDate]);
const handleModalClose = () => {
setShowModal(false);
setInputTitle('');
setInputDate('');
};
return (
<div className="app-container">
<div className="day">
<h3>오늘은 {todayDate}</h3>
{firstMeetDate && <p>처음 만난 날로부터 {firstMeetDays}일이 지났어요!</p>}
{anniversaries.map((anniversary, index) => (
<div key={index} className="anniversary">
<h3>{anniversary.title} _✏️{remainingTime[index]?.days}일</h3>
{remainingTime[index] && (
<p>남은 시간: {remainingTime[index].days}일 {remainingTime[index].hours}시간 {remainingTime[index].minutes}분 {remainingTime[index].seconds}초</p>
)}
</div>
))}
<button onClick={() => setShowModal(true)}>새로운 기념일 추가</button>
<input type="date" value={firstMeetDate} onChange={(e) => setFirstMeetDate(e.target.value)} />
<button onClick={() => setFirstMeet(firstMeetDate)}>처음 만난 날 설정</button>
</div>
{showModal && (
<div className="modal">
<div className="modal-content">
<span className="close" onClick={handleModalClose}>x</span>
<h2>새로운 기념일 추가</h2>
<input type="text" placeholder="기념일 제목" value={inputTitle} onChange={(e) => setInputTitle(e.target.value)} />
<input type="date" value={inputDate} onChange={(e) => setInputDate(e.target.value)} />
<button onClick={addNewAnniversary}>확인</button>
</div>
</div>
)}
</div>
);
}
function formatDate(date) {
const year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month < 10 ? `0${month}` : month;
day = day < 10 ? `0${day}` : day;
return `${year}-${month}-${day}`;
}
export default App;
여기까지 해보고 깨닳은점
import React, { useState, useEffect } from "react";
import "./App.css";
function App() {
const [anniversaries, setAnniversaries] = useState([]); //D-DAY목록
const [inputValues, setInputValues] = useState({ title: '', date: '' }); //입력폼
const [todayDate, setTodayDate] = useState(formatDate(new Date())); //현재날짜
const [firstMeetDate, setFirstMeetDate] = useState(''); //처음만난 날
const [firstMeetDays, setFirstMeetDays] = useState(0); ///처음 만나 날로부터 경과하 일 수
const [showModal, setShowModal] = useState(false); ///모달 표시여부
const [showFirstMeetForm, setShowFirstMeetForm] = useState(false); //처음 만난 날 설정 폼 표시여부
const addNewAnniversary = () => {
if (inputValues.title && inputValues.date) {
const selectedDate = new Date(inputValues.date).getTime();
const today = new Date(todayDate).getTime();
if (selectedDate >= today) {
setAnniversaries((prevAnniversaries) => [
...prevAnniversaries,
{ title: inputValues.title, date: inputValues.date }
]);
setInputValues({ title: '', date: '' });
handleModalClose();
} else {
alert("날짜를 현재 날짜 이후로 선택해주세요.");
}
}
};
const setFirstMeet = (selectedDate) => {
if (selectedDate) {
const today = new Date(todayDate).getTime();
const meetDay = new Date(selectedDate).getTime();
const gap = today - meetDay;
const daysDifference = Math.floor(gap / (1000 * 60 * 60 * 24));
if (daysDifference >= 0) {
setFirstMeetDate(selectedDate);
setFirstMeetDays(daysDifference);
} else {
alert("날짜를 현재 날짜 이전으로 선택해주세요.");
}
}
};
useEffect(() => {
const intervalId = setInterval(() => {
const now = new Date().getTime();
setAnniversaries((prevAnniversaries) => {
return prevAnniversaries.map((anniversary) => {
const dday = new Date(anniversary.date).getTime();
const gap = dday - now;
return {
...anniversary,
remainingTime: {
days: Math.floor(gap / (1000 * 60 * 60 * 24)),
},
};
});
});
}, 1000);
return () => clearInterval(intervalId);
}, []);
useEffect(() => {
setFirstMeet(firstMeetDate);
}, [firstMeetDate, todayDate]);
const handleModalClose = () => {
setShowModal(false);
setInputValues({ title: '', date: '' });
setShowFirstMeetForm(false);
};
return (
<div className="app-container">
<div className="day">
<h3>오늘은 {todayDate}</h3>
{firstMeetDate && <p>우리만난지 {firstMeetDays}일</p>}
<button onClick={() => setShowFirstMeetForm(true)}>처음 만난 날 설정</button>
{showFirstMeetForm && (
<div>
<input type="date" value={firstMeetDate} onChange={(e) => setFirstMeetDate(e.target.value)} />
<button onClick={() => { setFirstMeet(firstMeetDate); setShowFirstMeetForm(false); }}>확인</button>
</div>
)}
<button onClick={() => setShowModal(true)}>New D-day</button>
{anniversaries.map((anniversary, index) => (
<div key={index} className="anniversary">
<h3>{anniversary.title} _✏️{Math.max(0, anniversary.remainingTime?.days)}일</h3>
</div>
))}
{showModal && (
<div className="modal">
<div className="modal-content">
<span className="close" onClick={handleModalClose}>x</span>
<h2>New D-day</h2>
<input
type="text"
placeholder="기념일 제목"
value={inputValues.title}
onChange={(e) => setInputValues({ ...inputValues, title: e.target.value })}
/>
<input
type="date"
value={inputValues.date}
onChange={(e) => setInputValues({ ...inputValues, date: e.target.value })}
/>
<button onClick={addNewAnniversary}>확인</button>
</div>
</div>
)}
</div>
</div>
);
}
const formatDate = (date) => {
const year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month < 10 ? `0${month}` : month;
day = day < 10 ? `0${day}` : day;
return `${year}-${month}-${day}`;
};
export default App;