[React] 43. Home 페이지 기능 구현

서회정's avatar
Mar 18, 2026
[React] 43. Home 페이지 기능 구현

 

1. Next/Prev 버튼으로 날짜 변경

 
notion image
 
Next/Prev 버튼으로 월을 변경하는 로직을 만들자.
 
먼저 변경되는 상태를 관리하기 위해 useState 훅을 사용하자.
새로운 스테이트를 만들고 초기값을 현재 날짜로 지정해준다.
 
const [pivotDate, setPivotDate] = useState(new Date());
 
다음으로 각각의 버튼을 클릭했을 때 발생하는 이벤트 핸들러가 필요하다.
 
const onIncreaseMonth = () => {}; const onDecreaseMonth = () => {};
 
그러고 난 뒤 결과값을 렌더링하기 위해 리터럴 문법으로
상태로 관리되고 있는 날짜를 출력할 수 있게 하자.
 
js에서 월은 0부터 시작한다. 그래서 화면에는
현재 날짜보다 한 달 전의 날짜가 표시되는데
+1 하여 현재 날짜가 출력 될 수 있도록 하자.
 
그리고 각각의 버튼에 이벤트 핸들러를 넣어줬다.
 
<Header title={`${pivotDate.getFullYear()}${pivotDate.getMonth() + 1}월`} leftChild={<Button text={"<"} onClick={onDecreaseMonth} />} rightChild={<Button text={">"} onClick={onIncreaseMonth} />} />;
 
먼저 다음달로 넘어가는 클릭 이벤트를 만들자.
상태를 변경하기 위해 이벤트 핸들러 내부에서 setPivotDate 함수를 호출하자.
 
그리고 인수로 새로운 날짜 객체를 만들어서 현재 날짜인
pivotDate를 기준으로 년도와 월을 가져와 +1을 해주자.
 
const onIncreaseMonth = () => { setPivotDate(new Date(pivotDate.getFullYear(), pivotDate.getMonth() + 1)); };
 
날짜가 잘 넘어간다.
지난달로 이동하는 버튼의 이벤트도 만들자.
 
notion image
 
const onDecreaseMonth = () => { setPivotDate(new Date(pivotDate.getFullYear(), pivotDate.getMonth() - 1)); };
 

2. 변경된 날짜의 일기 랜더링

 
변경된 날짜의 일기 리스트를 화면에 렌더링 해보자.
 
먼저 우리가 만들어둔 목업 데이터를 수정해야한다.
현재 목업데이터로 만든 일기들은 프로그램을 실행하는
당시의 날짜로 세팅되어있다.
 
따라서 우리가 날짜 상태가 변경됨에 따라
동일한 날짜에 작성된 일기가 렌더링 될 수 있게 하려면
테스트를 위해 보다 다양한 목업데이터가 필요하다.
 
notion image
 
App컴포넌트 외부에 있는 목업 데이터의 일기 세 개를
프로젝트를 만들고 있는 날짜를 기준으로 잡아 현재 날짜,
어제, 저번 달로 나누어 수정해주었다.
 
다음으로 목업 데이터를 관리하는 스테이트를
Context를 통해 Home 컴포넌트로 전달해주어야한다.
 
이미 프로바이더 컴포넌트로 감싸져있는 구조이기 때문에
상태를 바로 넘겨주기 위해 DiaryStateContext
내보내주기만 하면 된다.
 
notion image
 
export문을 추가했다.
DiaryDispatchContext도 미리 내보내주었다.
 
export const DiaryStateContext = createContext(); export const DiaryDispatchContext = createContext();
 
다음으로는 Home 컴포넌트에서 useContext 훅을 추가해주고
DiaryStateContext 도 불러와주자.
 
그리고 Home 컴포넌트 내부에서 useContext의 인수로
DiaryStateContext를 넣어 App컴포넌트에서 data
전달되고있는 목업 데이터의 일기 리스트 상태를 data라는
변수에 할당해준다.
 
const data = useContext(DiaryStateContext);
 
다음으로 일기를 실질적으로 필터링하는 함수를 만들어주자.
인수로는 pivotData와 상태로 관리되는 일기 데이터인 data
받아주도록 하자.
 
// 이번달 일기만 필터링하는 함수 const getMonthlyData = (pivotDate, data) => {};
 
반환하는 값으로 전체 일기 리스트인 data를 필터링하여
item의 작성 날짜가 현재 날짜가 속한 달의 처음과 끝
사이에 있는 값만 찾아주어야한다.
 
// 이번달 일기만 필터링하는 함수 const getMonthlyData = (pivotDate, data) => { return data.filter( (item) => beginTime <= item.createdData && item.createdData <= endTime ); };
 
그래서 이 필터 메서드의 기능을 완성하기 위해서는
pivotDatebeginTimeendTime을 찾아야한다.
 
필터링 함수 내부에 새로운 Date객체를 만들어
인수로 pivotDate의 년도와 월, 그리고 시작과 끝의
날짜, 시간, 분, 초까지 작성하여 두 가지 기준점을 만들어주자.
 
// 이번달 일기만 필터링하는 함수 const getMonthlyData = (pivotDate, data) => { const beginTime = new Date( pivotDate.getFullYear(), pivotDate.getMonth(), 1, 0, 0, 0, ).getTime(); const endTime = new Date( pivotDate.getFullYear(), pivotDate.getMonth() + 1, 0, 23, 59, 59, ).getTime(); return data.filter( (item) => beginTime <= item.createdDate && item.createdDate <= endTime, ); };
 
Home컴포넌트 내부로 돌아와 만들어두었던
필터링 함수를 호출하고 인수로 pivotDatedata
전달하여 저장된 값을 monthlyData로 저장해준다.
 
그리고 콘솔에서 출력해보자.
 
const monthlyData = getMonthlyData(pivotDate, data); console.log(monthlyData);
 
위에서 설정된 날짜에 해당하는 달의 일기가
필터링되어 콘솔에 출력된다.
 
notion image
 
이 값을 DiaryList 컴포넌트에 props로 전달해주자.
 
notion image
 
다이어리리스트 컴포넌트에서는 이를 props로 받는다.
 
notion image
 
다음으로 일기 리스트안에 map메서드를 통해 배열을
순회하면서 뿌릴 수 있도록 해주자.
 
map 메서드를 사용할 때 각 컴포넌트에 key값이 필요하며
콜백함수의 매개변수로 넣었던 itemid를 넣어주자.
 
그리고 props로 각각의 item이 가지고 있는 값들을
뿌려서 전달하자.
 
<div className="list_wrapper"> {data.map((item) => ( <DiaryItem key={item.id} {...item} /> ))} </div>;
 
DiaryItem 컴포넌트에서 아까 전개연산자로 뿌린
각 props를 객체 형태로 받아와주자.
 
notion image
 
임시로 넣어두었던 emotionId는 삭제하고 하나의 일기
아이템에 들어가는 각각의 값을 넣어주자.
 
return ( <div className="DiaryItem"> <div className={`img_section img_section_${emotionId}`}> <img src={getEmotionImage(emotionId)} alt="" /> </div> <div className="info_section"> <div className="created_date"> {new Date(createdDate).toLocaleDateString()} </div> <div className="content">{content}</div> </div> <div className="button_section"> <Button text={"수정하기"} /> </div> </div> );
 
선택한 달에 맞는 데이터가 렌더링된다!
 
notion image
notion image
 

3. 각 일기에 맞는 페이지 라우팅

 
하나의 일기에 이모션 영역이나 인포영역을 클릭했을 땐
해당 일기에 맞는 상세보기 화면으로 이동해야한다.
 
그리고 수정하기 버튼을 클릭했을 때도 마찬가지로
해당 일기의 수정 페이지로 이동해야한다.
이러한 라우팅 작업을 같이 진행해보자.
 
notion image
 
우선 리액트 라우터 돔에서 제공하는
useNavigate 커스텀 훅을 불러와주자.
 
import { useNavigate } from "react-router-dom";
 
다음으로는 리터럴 문법을 통해 해당 요소를 클릭했을 때
넘어가는 페이지의 id를 유동적으로 받아 이동할 수 있게 해주자.
 
return ( <div className="DiaryItem"> <div onClick={() => nav(`/diary/${id}`)} className={`img_section img_section_${emotionId}`} > <img src={getEmotionImage(emotionId)} alt="" /> </div> <div className="info_section" onClick={() => nav(`/diary/${id}`)}> <div className="created_date"> {new Date(createdDate).toLocaleDateString()} </div> <div className="content">{content}</div> </div> <div className="button_section"> <Button onClick={() => nav(`/edit/${id}`)} text={"수정하기"} /> </div> </div> );
 

4. 새 일기 쓰기 라우팅

 
notion image
 

5. 정렬 필터

 
최신순, 오래된 순으로 일기를 렌더링 해보자.
 
먼저 select태그 내부에 있는 두 가지 옵션의 값을
저장하고 관리하기 위해 useState 훅을 불러오자.
 
그러고 난 뒤 새로운 상태를 만들어 초기값으로
최신순 옵션의 value값인 latest를 넣어두자.
 
const [sortType, setSortType] = useState("latest");
 
그리고 실질적인 옵션 변경의 이벤트 핸들러를 만들자.
이벤트 객체인 e를 매개변수로 받아 솔트타입을 변경시키는
함수 setSortType을 호출하고 매개변수로
e.target.value를 받아주자.
 
const onChangeSortType = (e) => { setSortType(e.target.value); };
 
이를 select 태그의 onChange 이벤트에 넣어주자.
 
<select onChange={onChangeSortType}> <option value={"latest"}>최신순</option> <option value={"oldest"}>오래된 순</option> </select>;
 
화면에 변경된 값으로 렌더링해서 보여주기 위해
솔팅을 통헤 변경된 값으로 일기데이터를 저장해서
전달해야한다.
 
비교식을 만드는데 원본 데이터를 건들지 않고
비교하여 새로운 배열을 반환하는 toSorted메서드를
사용해주도록 하자.
 
그리고 현재 비교를 진행하는 data는 객체이기 때문에
사전순으로 비교하는 메서드를 사용하려면 콜백함수로
직접 비교하는 과정이 필요하다.
 
const getSortedData = () => { return data.toSorted((a, b) => { if (sortType === "oldest") { return Number(a.createdDate) - Number(b.createdDate); } else { return Number(b.createdDate) - Number(a.createdDate); } }); };
 
마지막으로 datasortedData로 변경해주면 정렬 기능까지 완료이다.
 
{ sortedData.map((item) => <DiaryItem key={item.id} {...item} />); }
Share article

clubnerdy