본문 바로가기

TIL

TIL: React, Vite, Redux(RTK), Router를 이용한 SPA 블로그 프로젝트

프로젝트 개요

  1. 프로젝트 목표:
    •   로그인 기능이 있는 블로그 만들기
    •   로컬 스토리지 활용해 데이터 관리하기
    •   CRUD 기능을 포함한 블로그 시스템 구현하기
  2. 기술 스택:
    •   React: 프론트엔드 프레임워크
    •   Vite: 빠른 개발 환경 구축
    •   Redux (RTK): 상태 관리
    •   React Router: 클라이언트 사이드 라우팅
    •   Styled-components: 초기 스타일링
    •   Tailwind CSS: 스타일링 연습 (향후 컴포넌트에 적용)
    •   clsx: 조건부 스타일링 (향후 컴포넌트에 적용)

구현된 기능

  1. 로그인 및 회원가입 기능:
    •   로그인 상태에 따라 글쓰기 버튼 및 로그아웃 버튼 표시
    •   모달창을 이용한 회원가입 및 로그인 전환
  2. 블로그 글쓰기 및 글 목록 표시:
    •   로그인된 상태에서 글 작성 시, 회원 ID와 이름을 로컬 스토리지에 저장
    •   글 목록에 작성자, 제목, 내용, 날짜 표시
  3. 리덕스 상태 관리:
    •   auth.slice: 로그인 상태 관리
    •   modal.slice: 모달 상태 관리
    •   post.slice: 게시글 상태 관리

현재까지의 작업

  1. 로그인 및 회원가입 기능 구현:
    •   로그인 상태에 따라 UI 요소 동적 표시
    •   회원가입 및 로그인 모달창 간 전환 가능
  2. 글 작성 및 글 목록 표시:
    •   글쓰기 버튼 클릭 시 글쓰기 폼으로 이동
    •   작성된 글을 로컬 스토리지에 저장 및 화면에 표시
  3. 리덕스 상태 관리:
    •   중앙 집중식 상태 관리로 효율적인 상태 업데이트

현재까지 블로그 기능

문제 발생 및 해결 방안

문제 1: 로그인 상태 관리 문제

  • 문제: 로그인 폼에서 로그인을 할 때 Redux를 활용하여 로그인 상태와 로컬 스토리지에 ID와 닉네임을 저장한 후, 글 작성 시 store에서 관리하고 있는 현재 로그인된 ID와 닉네임을 불러와 해당 글을 현재 로그인 상태인 사람의 ID로 저장하려 했습니다. 그러나 페이지를 나가고 난 뒤 글 작성 폼에서 상태를 불러올 때 undefined가 나오는 문제가 발생했습니다.
  • 해결 방안: localStorage.getItem("login")을 사용하여 로그인 데이터를 불러오고, JSON.parse()로 전환한 뒤 const { id: userId, name: userName } = userObject로 데이터를 불러오는 방식으로 문제를 일단 해결했습니다. 하지만 이 해결방안이 올바른 해결 방안이라고 생각하지 않아서 개선해야 할 것 같습니다.

문제 2: 모달창 전환 기능 개선

  • 문제: 초기에는 로그인 <-> 회원 가입 모달창 전환 기능을 props로 받아서 처리했습니다. 이는 코드의 가독성을 떨어뜨렸습니다.
  • 해결 방안: 모달 컴포넌트 파일에서 slice 액션을 사용하여 dispatch로 모달창을 닫고 원하는 모달창을 여는 방식으로 변경하여 코드가 더 직관적이고 props를 받지 않아도 되도록 개선했습니다.

앞으로의 작업 및 개선 사항

  1. 글 편집 페이지 구현:
    •   EditPostPage를 통해 글 수정 기능 추가
  2. 상세 페이지에서 글 수정 및 삭제 기능 구현:
    •   PostDetailPage에서 Update 및 Delete 기능 추가
  3. 리덕스 미들웨어 활용:
    •   로컬 스토리지와 상호 작용하는 미들웨어 추가
  4. 코드 리팩토링:
    •   중복된 코드 제거 및 불필요한 리렌더링 최소화
  5. 스타일링 개선:
    •   Tailwind CSS로 스타일링 변경 및 연습
    •   조건부 스타일링을 위해 clsx 라이브러리 사용

프로젝트 폴더 구조

speed
02-blog
├─ .eslintrc.cjs
├─ index.html
├─ jsconfig.json
├─ package-lock.json
├─ package.json
├─ postcss.config.js
├─ public
│  └─ vite.svg
├─ README.md
├─ src
│  ├─ App.jsx
│  ├─ assets
│  │  └─ react.svg
│  ├─ components
│  │  ├─ auth
│  │  │  ├─ LoginForm
│  │  │  │  ├─ index.js
│  │  │  │  ├─ LoginForm.jsx
│  │  │  │  └─ LoginForm.styled.js
│  │  │  └─ RegisterForm
│  │  │     ├─ index.js
│  │  │     ├─ RegisterForm.jsx
│  │  │     └─ RegisterForm.styled.js
│  │  ├─ Modal
│  │  │  ├─ AlertModal
│  │  │  │  ├─ AlertModal.jsx
│  │  │  │  ├─ AlertModal.styled.js
│  │  │  │  └─ index.js
│  │  │  ├─ LoginModal
│  │  │  │  ├─ index.js
│  │  │  │  ├─ LoginModal.jsx
│  │  │  │  └─ LoginModal.styled.js
│  │  │  ├─ ModalContainer
│  │  │  │  ├─ index.js
│  │  │  │  ├─ ModalContainer.jsx
│  │  │  │  └─ ModalContainer.styled.js
│  │  │  └─ RegisterModal
│  │  │     ├─ index.js
│  │  │     ├─ RegisterModal.jsx
│  │  │     └─ RegisterModal.styled.js
│  │  └─ posts
│  │     ├─ PostEditor
│  │     │  ├─ index.js
│  │     │  └─ PostEditor.jsx
│  │     ├─ PostForm
│  │     │  ├─ index.js
│  │     │  ├─ PostForm.jsx
│  │     │  └─ PostForm.styled.js
│  │     ├─ PostItem
│  │     │  ├─ index.js
│  │     │  └─ PostItem.jsx
│  │     └─ PostList
│  │        ├─ index.js
│  │        └─ PostList.jsx
│  ├─ GlobalStyle.js
│  ├─ index.css
│  ├─ layouts
│  │  ├─ common
│  │  │  ├─ Footer
│  │  │  │  ├─ Footer.jsx
│  │  │  │  ├─ Footer.styled.js
│  │  │  │  └─ index.js
│  │  │  └─ Header
│  │  │     ├─ Header.jsx
│  │  │     ├─ Header.styled.js
│  │  │     └─ index.js
│  │  ├─ MainLayout
│  │  │  ├─ index.js
│  │  │  ├─ MainLayout.jsx
│  │  │  └─ MainLayout.styled.js
│  │  └─ Pagination
│  │     ├─ index.js
│  │     └─ Pagination.jsx
│  ├─ main.jsx
│  ├─ pages
│  │  ├─ EditPostPage
│  │  │  ├─ EditPostPage.jsx
│  │  │  └─ index.js
│  │  ├─ HomePage
│  │  │  ├─ HomePage.jsx
│  │  │  └─ index.js
│  │  ├─ NewPostPage
│  │  │  ├─ index.js
│  │  │  └─ NewPostPage.jsx
│  │  └─ PostDetailPage
│  │     ├─ index.js
│  │     └─ PostDetailPage.jsx
│  ├─ redux
│  │  ├─ slices
│  │  │  ├─ auth.slice.js
│  │  │  ├─ modal.slice.js
│  │  │  └─ post.slice.js
│  │  └─ store.js
│  └─ router
│     └─ router.jsx
├─ tailwind.config.js
└─ vite.config.js