React/실습 정리
React 7강 - Todo 읽기(Read)·목록(List) 컴포넌트 & 커스텀 훅 구현
코딩하는냥이
2025. 7. 31. 09:47
반응형
이번 글에서는 서버에서 Todo 데이터를 읽어서 보여주는 컴포넌트(ReadComponent, ListComponent)
그리고 페이지 이동/쿼리 파라미터 처리를 쉽게 해주는 커스텀 훅(useCustomMove) 구현 방법을 배우겠습니다.
1. Todo 상세 조회 컴포넌트(ReadComponent.js) 생성
src/components/ReadComponent.js
import { useEffect, useState } from "react"
import { getOne } from "../../api/todoApi"
import useCustomMove from "../../hooks/useCustomMove"
const initState = {
tno: 0,
title: '',
writer: '',
dueDate: null,
complete: false
}
const makeDiv = (title, value) =>
<div className="flex justify-center">
<div className="relative mb-4 w-full flex flex-wrap items-stretch text-lg">
<div className="w-1/5 p-6 text-right font-bold">{title}</div>
<div className="w-4/5 p-6 rounded-r border border-solid shadow-md">{value}</div>
</div>
</div>
const ReadComponent = ({ tno }) => {
const [todo, setTodo] = useState(initState)
const {moveToList, moveToModify} = useCustomMove()
useEffect(() => {
getOne(tno).then(data => {
console.log(data)
setTodo(data)
})
}, [tno])
return (
<div className="border-2 border-sky-200 mt-10 m-2 p-4">
{makeDiv('번호', todo.tno)}
{makeDiv('작성자', todo.writer)}
{makeDiv('제목', todo.title)}
{makeDiv('작성일자', todo.dueDate)}
{makeDiv('수정', todo.complete ? '수정':'아니요')}
<div className="flex justify-end">
<button type="button" className="rounded p-4 m-2 text-xl w-32 text-white bg-blue-500" onClick={()=>moveToList()}>List</button>
<button type="button" className="rounded p-4 m-2 text-xl w-32 text-white bg-red-500" onClick={()=>moveToModify(todo.tno)}>Modify</button>
</div>
</div>
)
}
export default ReadComponent;
2. 커스텀 훅(useCustomMove.js) 구현
src/hooks/useCustomMove.js
import { createSearchParams, useNavigate, useSearchParams } from "react-router-dom";
const getNum = (param, defaultValue) => {
if (!param) return defaultValue;
return parseInt(param);
}
const useCustomMove = () => {
const navigate = useNavigate()
const [queryParams] = useSearchParams()
const page = getNum(queryParams.get("page"), 1)
const size = getNum(queryParams.get("size"), 10)
const queryDefault = createSearchParams({ page, size }).toString()
const moveToList = (pageParam) => {
let queryStr = ""
if (pageParam) {
const pageNum = getNum(pageParam.page, 1)
const sizeNum = getNum(pageParam.size, 10)
queryStr = createSearchParams({ page: pageNum, size: sizeNum }).toString()
} else {
queryStr = queryDefault
}
navigate({pathname:'../list', search:queryStr})
}
const moveToModify = (num) => {
navigate({
pathname:`../modify/${num}`,
search:queryDefault
})
}
return {moveToList, page, size, moveToModify}
}
export default useCustomMove;
- 설명:
- 현재 URL 쿼리(page, size)값을 자동으로 추출해서,
리스트/수정 페이지 이동 시 쿼리스트링이 항상 유지되게 처리합니다.
- 현재 URL 쿼리(page, size)값을 자동으로 추출해서,
3. ReadPage에서 컴포넌트 적용
src/pages/todo/ReadPage.js
(중요 부분만)
import ReadComponent from "../../components/ReadComponent";
const ReadPage = ({ tno }) => {
return (
<div>
<ReadComponent tno={tno} />
</div>
);
};
4. Todo 목록 컴포넌트(ListComponent.js) 생성
src/components/ListComponent.js
import { useEffect, useState } from "react";
import useCustomMove from "../../hooks/useCustomMove";
import { getList } from "../../api/todoApi";
const initState = {
dtoList:[],
pageNumList:[],
pageRequestDTO:null,
prev:false,
next:false,
totalCount:0,
prevPage:0,
nextPage:0,
totalPage:0,
current:0
}
const ListComponent = () => {
const {page, size} = useCustomMove()
const [serverData, setServerData] = useState(initState)
useEffect(() => {
getList({page, size}).then( data => {
setServerData(data)
})
}, [page, size])
return(
<div className="border-2 border-blue-100 mt-10 mr-2 ml-2">
<div className="flex flex-wrap mx-auto justify-center p-6">
{serverData.dtoList.map( todo =>
<div key={todo.tno} className="w-full min-w-[400px] p-2 m-2 rounded shadow-md">
<div className="flex">
<div className="font-extrabold text-2xl p-2 w-1/12">{todo.tno}</div>
<div className="font-extrabold text-xl m-1 p-2 w-8/12">{todo.writer}</div>
<div className="font-medium text-xl m-1 p-2 w-3/12">{todo.dueDate}</div>
</div>
</div>
)}
</div>
</div>
)
}
export default ListComponent;
💡 포인트 정리
- useCustomMove 훅을 사용하면,
페이징 쿼리스트링이 자동으로 관리되어
페이지 간 이동이나 수정 시 값이 보존됨 - ReadComponent / ListComponent에서
API 데이터 받아와서 상태관리 & 화면 출력 - 코드 분리로 컴포넌트/훅 재사용성이 높아짐
📌 정리하자면, 이번 강의에서는 서버에서 받아온 Todo 데이터로 상세/목록 페이지를 구현하고, 페이지 이동 및 쿼리 관리까지 쉽게 만드는 커스텀 훅의 활용법을 실습했습니다.