🔑 남들보다 10분 더 앉아있기...
💡 프로젝트 소개 및 개요
📃 프론트엔드 교육을 마치며, 배운 내용을 복습하고 정리하기 위해 간단한 지식 공유 웹 애플리케이션을 구현했습니다. 기존 프로젝트의 코드를 리팩토링하고 개선하여 제작한 이번 프로젝트는 학습 내용을 실전에 적용하고, 개발 프로세스를 다시 점검해볼 좋은 기회였습니다
💡 메인 Home
📃 Home 페이지는 Header와 PostList로 나뉩니다
🔍 Header: 커스텀 컴포넌트로 구현되어 다른 페이지에서도 재사용이 가능합니다
🔍 PostList: map 함수를 사용해 데이터를 순회하며 PostItem 컴포넌트를 렌더링합니다
💻CODE
// 커스텀 헤더
<Header
title={`${pivotDate.getFullYear()}년 ${pivotDate.getMonth() + 1}월`}
leftChild={<Button text={"◀"} onClick={onDecreaseMouth} />}
rightChild={<Button text={"▶"} onClick={onIncreaseMouth} />}
/>
// PostList
<div className="list_wrapper">
{sortedDate.map((item) => {
return (
<PostItem key={item.id} {...item} />
)
})}
</div>
💡새로운 글 작성 페이지 (New)
📃 오늘 교육에서 배웠던 React Router를 사용해 Home에서 "새 지식 쓰기" 버튼 클릭 시 New 페이지로 이동합니다. 사용자는 날짜, 주제, 그리고 내용을 입력해 새로운 포스트를 작성할 수 있습니다.
💻CODE
import { useNavigate } from "react-router-dom";
import Header from "../components/Header";
import Button from "../components/Button";
import Editor from "../components/Editor";
import { PostDispatchContext } from "../App";
import { useContext } from "react";
const New = () => {
const nav = useNavigate()
const { onCreate } = useContext(PostDispatchContext)
const onSubmit = (input) => {
onCreate(input.createdDate.getTime(), input.logoId, input.content);
nav("/", { replace: true })
}
return (
<>
<Header leftChild={<Button text={"< 뒤로가기"} onClick={() => nav(-1)} />} title={"새로운 포스트"} />
<Editor onSubmit={onSubmit} />
</>
)
}
export default New;
⬆️ 코드를 작성하면서 느낀점은 구현하려고 하는 어떤 Form에 대해서 레이아웃을 먼저 잡고(컴포넌트로 어떻게 나눌지 고민) 그리고 기능을 구현하는 순서가 효율적인 것 같습니다
💡 글 수정 페이지 (Edit)
📃 Edit 페이지는 New 페이지에서 사용한 Editor라는 컴포넌트를 똑같이 사용을 합니다. New 페이지에서는 모두 빈칸으로 존재하지만, Edit페이지에서는 초기 데이터를 전달받아, 기존 작성된 내용을 보여줘야합니다.
💻CODE
const Editor = ({ initData, onSubmit }) => {
...
useEffect(() => {
if (initData) {
setInput({
...initData,
createdDate: new Date(Number(initData.createdDate))
})
}
}, [initData])
return (
...
)}
export default Editor
⬆️ 이러한 로직의 핵심은 initData와 onSubmit 함수를 props로 받아서 New 버튼이 눌릴때와 Update 버튼이 눌릴때의 이벤트처리를 따로 해줘야한다는 점하고, useEffect의 의존성 배열을 빈배열로 받아 초기렌더링에서 initData가 존재한다면, form을 data로 초기화해준다는 점입니다
💡글 상세 보기 페이지 (Post)
📃 Post 페이지는 Home에서 PostItem을 클릭하면 Route 되고, 커스텀 헤더와 Viewer 컴포넌트로 보여지게 됩니다. 사실 그냥 데이터 가져와서 보여주면 되는 부분이라 크게 어려운 것은 없고, id에 따라서 매핑을 해줘야하기때문에 CustomHook을 하나 만들어서 처리해줘야합니다
💻CODE
// Post 페이지
const Post = () => {
const param = useParams();
const curPostItem = usePost(param.id)
const { createdDate, logoId, content } = curPostItem;
return (
<div>
<Header title={title}
leftChild={<Button text={"< 뒤로가기"} onClick={() => nav(-1)} />}
rightChild={<Button onClick={() => nav(`/edit/${param.id}`)} text={"수정하기"} />}
/>
<Viewer logoId={logoId} content={content} />
</div>
)
}
export default Post
// usePost 훅
const usePost = (id) => {
const data = useContext(PostStateContext);
const [curPostItem, setCurPostItem] = useState();
const nav = useNavigate();
useEffect(() => {
const currentPostItem = data.find((item) => String(item.id) === String(id))
if (!currentPostItem) {
window.alert("존재하지 않는 포스트입니다");
nav("/", { replace: true })
}
setCurPostItem(currentPostItem)
}, [id])
return curPostItem
}
export default usePost;
⬆️ 일단 useParams를 통해서 내가 선택한 PostItem의 id를 가지고 올 수 있습니다. 이렇게 가져온 id를 바탕으로 데이터를 조회하기 위해 커스텀 훅을 구현했고, 이 커스텀 훅은 props로 전달 받은 id를 기반으로 데이터를 검색하고 반환하며, 반환된 데이터를 구조 분해 할당을 통해 효율적으로 처리 할 수 있습니다
💡Vercel 배포
📃 마지막으로 Vercel에 배포를 위해, npm run build를 통해서 내가 만든 프로젝트가 빌드되는지 확인하고, 만약 문제가 있다면, 여기에 나타납니다.
⬆️ Vercel을 통해서 너무 간단하게 배포할 수 있습니다
https://study-amaze.vercel.app/
AMaze 일기장
새로움 배움을 나눠보아요
study-amaze.vercel.app