![썸네일](https://private-user-images.githubusercontent.com/96939334/307419264-afac3c56-a9a4-4ff0-ab6d-9a0376d078bb.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4OTExNTAsIm5iZiI6MTcyMzg5MDg1MCwicGF0aCI6Ii85NjkzOTMzNC8zMDc0MTkyNjQtYWZhYzNjNTYtYTlhNC00ZmYwLWFiNmQtOWEwMzc2ZDA3OGJiLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MTclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODE3VDEwMzQxMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNlNjI1YTVhODIxNTNjYmViZDk3NjA4MTk5ZWFlZTQzMjZiYjk4MDA5YTM4NzkxNDkzZmY1ZWZkNzcyNDgzZWMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.cRwJpa0jCz4Ql8TgWVi9_yoGz6Q9WNC91r1OWBAgq9I)
타닥타닥은 캠핑의 낭만적인 순간을 기록하여 자신만의 캠핑 이야기를 공유하고, 캠핑 용품들을 중고거래할 수 있는 SNS입니다.
- 타닥타닥 서비스는 캠핑을 즐기는 누구나 이용할 수 있는 SNS입니다.
- 글과 사진을 함께 게시물로 작성하여 자신만의 캠핑 이야기를 공유할 수 있습니다.
- 다른 사용자를 팔로우하지 않아도 추천 게시물을 통해 많은 사람들의 캠핑 이야기를 확인할 수 있고, 팔로우를 통해 홈 피드에서는 팔로잉을 한 사용자의 글을 볼 수 있습니다. 댓글과 좋아요를 통해 직접 소통할 수도 있습니다.
- 사용자가 직접 각종 캠핑 상품을 등록하여 다른 사용자들과 중고거래 할 수 있습니다.
🏕 배포 URL
타닥타닥 테스트 계정
ID : [email protected]
PW : tadaktadak
안동섭 | 김지원 | 박지은 | 조원영 |
---|---|---|---|
DongSup_Ahn | jiwon6635 | Eunnnnnnnn | JoWonYeong |
팀장 | 팀원 | 팀원 | 팀원 |
프론트엔드 | 백엔드 | 디자인 | 협업방식 |
---|---|---|---|
멋쟁이사자처럼에서 제공된 API 사용 |
프로젝트 개발기간
2023.06.01 - 2023.06.30리팩토링 개발기간
2023.07.18 - 2023.10.04![]()
![]()
- 회원가입
- 로그인 / 로그아웃
- 유저 검색
- 스토리 보기
- 게시물 목록 보기
- 좋아요 / 좋아요 취소
- 게시물 조회 / 작성 / 수정 / 삭제 / 신고
- 댓글 조회 / 작성 / 수정 / 삭제 / 신고
- 상품 조회 / 작성 / 수정 / 삭제
- 프로필 조회 / 수정
- 팔로워, 팔로잉 조회 / 수정
스플래시 | 회원가입 | 로그인 |
---|---|---|
게시글 | 게시글 상세 |
---|---|
게시글 작성 | 상품등록 |
---|---|
📱 |
---|
📱 |
---|
📱 |
---|
게시글수정 | 게시글삭제 | 게시글신고 |
---|---|---|
댓글삭제 | 상품삭제 | 로그아웃 |
---|---|---|
📱 |
---|
PC화면 |
---|
팔로우추천영역 |
---|
Mobile | PC |
---|---|
문제
: 모바일 뷰를 주요 고려 대상으로 삼아 웹 페이지를 개발함으로써,
다양한 PC 화면 크기와 해상도에 대응하지 못하는 문제가 발생했습니다.
이로 인해 사용자 경험이 일관되지 않아지는 문제가 예상되었습니다.해결
: 미디어 쿼리를 활용으로 PC 반응형 디자인을 적용하여 웹 페이지가 다양한 PC 환경에서 최적으로 표시되도록 조정하였습니다.
더불어, PC 버전에서의 헤더와 네브바를 추가하고, 계정 추천 영역을 추가하여 개별 기능을 강화하였습니다.
이로써 PC 사용자들이 다양한 화면 크기와 해상도에서 웹 페이지를 원활하게 이용할 수 있게 되었습니다.
문제
: 계정 검색 시에 사용자가 글자를 입력할 때마다 매번 검색 요청이 발생하여
데이터 트래픽 증가로 인해 서버에 불필요한 부하가 발생하는 문제가 있었습니다.
또한, 사용자가 검색어 입력을 완료하지 않은 상태에서 결과가 표시되다보니 부정확한 결과가 표시되어 사용자 경험이 저하되는 문제도 있었습니다.해결
: 계정 검색에 디바운스를 적용하여, 사용자가 글자를 입력하는 동안 일정 시간 동안 검색 요청을 지연시켰습니다.
따라서, 연속된 검색 요청을 방지하고, 사용자가 입력을 마친 후 한 번의 검색 요청을 처리하도록 할 수 있었습니다.
이로써, 서버 부하를 감소시키고 사용자가 더 효과적으로 계정을 검색할 수 있게 되었습니다.
문제
: 모든 이미지가 페이지 로딩 시 동시에 다운로드 되어 초기 페이지 로딩 속도가 느려지는 문제가 있었습니다.
특히 대용량 이미지 파일이 많은 경우 초기 로딩 시간이 길어져 사용자가 페이지 로딩에 상대적으로 더 많은 시간을 소비하게 되었습니다.해결
: 이미지 레이지 로딩을 도입하여, 초기 페이지 로딩 시에는 이미지를 포함하지 않는 기본 내용만을 로드하도록 했습니다.
그 다음, 사용자가 스크롤하거나 이미지가 화면에 나타나야 할 때 해당 이미지만 비동기적으로 로딩되도록 조정하였습니다.
이로써 초기 페이지 로딩 속도가 개선되었으며, 사용자가 페이지 로딩을 기다리는 시간을 단축시켰습니다.
문제
: 대용량 이미지 파일이 웹 페이지에 업로드되는 경우,
해당 이미지를 로딩하는 과정에서 용량이 상대적으로 작은 이미지보다 화면에 늦게 나타나게 되어
사용자가 이미지를 곧바로 확인하지 못하는 문제가 종종 있었습니다.해결
: 이미지 업로드 시 이미지 압축을 적용하여 이미지 파일의 크기를 줄였습니다.
이미지 압축을 통해 대역폭과 데이터 부하도 줄이며, 페이지 로딩 속도를 개선하여 사용자가 웹 페이지를 빠르게 로드할 수 있도록 하였습니다.
문제
: 잘못된 확장자로 파일 업로드를 할 경우 조건문으로 인해 동작되어야하는 state의 변화가 이루어지지 않아서,
사용자 입장에서 잘못된 접근임을 인지하기 어려웠습니다.해결
: useEffect Hook을 이용해서 state의 상태값의 변화를 감지하도록 하여
상태의 boolean 값에 따라 state의 변화를 일으키도록 했습니다.
이를 통해 상태값이 변화하지 않는 현상에 대응하고 처리할 수 있었습니다.
문제
: 프로필 페이지에서 탭바를 useState Hook으로 state를 관리하기 때문에,
다른 컴포넌트로 이동 후에 뒤로가기를 버튼을 누를 경우 설정해놓은 state의 초기값에 해당하는 탭바가 활성화됐었습니다.해결
: useParams Hook 이용해서 추출한 경로를 활용하여 유저 프로필 페이지에서 탭을 선택하고 해당하는 컨텐츠를 표시할 수 있게 했습니다.
문제
: 로그인 시 발생하는 실패 메시지가 인풋 필드에 값을 입력해도 자동으로 사라지지 않아, 사용자가 로그인을 진행하는데 불편하고 혼란스러웠습니다.해결
: 유효성 검사 로직을 개선하여 사용자가 로그인을 실패한 후, 사용자가 인풋 필드에 유효한 값을 입력할 때 실패 메시지가 자동으로 사라지도록 조정했습니다. 더불어, 사용자가 로그인 시도를 재시작하거나 입력을 수정하는 데 드는 시간을 최소화하기 위해 인풋 필드와 실패 메시지를 더 효율적으로 연동하도록 개선했습니다.
문제
: 회원가입을 완료한 후, 사용자는 스플래시 페이지를 통과한 후 로그인 페이지로 이동해야 했습니다.
이로 인해 사용자 경험이 불필요하게 지연되었고, 로그인 절차가 번거로웠습니다.해결
: 회원가입 프로세스를 완료한 후, 사용자를 스플래시 페이지가 아닌 직접 로그인 페이지로 리다이렉트하도록 조정했습니다.
이로써 사용자는 더 빠르게 로그인을 시작할 수 있으며, 웹 사이트를 더 원활하게 이용할 수 있게 되었습니다.
커밋 유형 | 커밋 메세지 | 의미 |
---|---|---|
💡 | :bulb: Feat: |
새로운 기능 추가 |
🐛 | :bug: Fix: |
버그수정 |
📚 | :books: Docs: |
문서 수정 |
♻️ | :recycle: Refactor: |
리팩토링 |
🎨 | :art: Design: |
CSS 등 사용자 UI 디자인 변경 |
💄 | :lipstick: Style: |
코드 포맷팅, 세미콜론 누락, 코드 변경이 없는 경우 |
💬 | :speech_balloon: Comment: |
필요한 주석 추가 및 변경 |
🌱 | :seedling: Init: |
프로젝트 초기 생성 |
🧸 | :teddy_bear: Chore: |
이외의 변경사항 |
✍🏻 | :writing_hand: Rename: |
파일 또는 폴더 명을 수정하거나 옮기는 작업만인 경우 |
🗑️ | :wastebasket: Remove: |
파일을 삭제하는 작업만 수행한 경우 |
🚀 | :rocket: Release: |
배포 |
Prettier에 대한 사용자 정의 설정
{
"tabWidth": 2, // 들여쓰기 간격을 2로 설정
"singleQuote": true, // 문자열에는 작은 따옴표를 사용
"semi": true, // 문장의 끝에 세미콜론을 추가
"printWidth": 80, // 한 줄의 최대 길이를 80으로 제한
"trailingComma": "es5" // ES5 문법에서만 뒷콤마를 허용
}
import 순서 규칙
// 1. hook
import { useState } from 'react';
import { Link } from 'react-router-dom';
// 2. styled-component
import styled from 'styled-components';
// 한줄 공백
// 3. import로 가져오는 컴포넌트 파일
import Album from '../common/Album';
// 한줄공백
// 4. 불러오는 이미지 파일
import postImg1 from './../../assets/testImg/post1.png';
import postImg2 from './../../assets/testImg/post2.png';
GitHub Flow
- 지속적인 배포를 진행하기 보다는 하나의 프로젝트가 완성되었을때 배포하는 개념이었기 때문에 지속적인 통합과 기능 개발에 중점을 두어 Git Flow 전략보다는 GitHub Flow 전략이 적합하다고 생각했습니다.
- 프로젝트 기간 동안 팀원들이 지속적으로 작업을 진행하기 때문에 충돌을 최소한으로 줄이고자 GitHub Flow 전략을 선택하였습니다.
- 빠른 피드백과 이슈를 생성 할 수 있었고, 체계적인 협력 규칙을 정해서 관리 하였기 때문에 필요 이상의 복잡함을 줄이고 효율적인 과정으로 기능개발을 진행할 수 있었습니다.
- 매주 월요일, 목요일 회의를 진행하여 세부적인 역할 분담을 하고 이슈를 생성합니다.
- 이슈 넘버에 맞게 각자 브랜치를 생성하여 지속적으로 작업을 진행합니다.
- 브랜치에서 작업이 완료되면 각자 브랜치에서 컨벤션에 맞게 커밋후 PR(Pull Request)을 오픈합니다.
- 다른 멤버들의 컨펌이 완료되면 main으로 merge합니다.
- 각자 맡은 작업 진행후 LiveShare을 통해 문제가 생긴 부분을 함께 수정하고 추가한 코드를 리뷰하고 이슈를 Close합니다.
FINAL-02-TA-DAK-TA-DAK
├── 📁node_modules
├── .gitignore
├── .prettierrc.json
├── package-lock.json
├── package.json
├── README.md
├── 📁public
├── 📂src
├── 📁api
├── 📂assets
├── 📁img
├── 📂components
├── 📁common
├── 📁header
├── 📁UserPostList
├── 📁hooks
├── 📂Loader
├── 📁img
├── 📁pages
├── 📁recoil
├── 📁Routes
├── 📂style
├── 📁theme
custom Hook 사용
useAlertControl
,useModalControl
- 모달컴포넌트를 감싸서 모달을 컨트롤 할 수 있는 훅을 생성했습니다.
- children 속성을 이용해서 컨트롤 하고자 하는 모달을 동적으로 받아와서 관리했습니다.
useScrollBottom
- 요소의 스크롤을 감지할 수 있는 훅을 생성했습니다.
- useRef Hook을 호출해서 객체를 생성하여 객체를 훅의 인자로 전달하고,
스크롤 이벤트를 감지하고 싶은 요소에 ref 속성을 전달하여 스크롤이 바닥에 닿을 때 작동하도록 했습니다.
useImageUploader
- 선택한 파일을 통해 유효성 검사를 하고 미리보기 URL과 업로드된 이미지의 URL을 반환해주는 훅을 생성했습니다.
- input 태그의 onChange 이벤트에서 선택한 파일을 통해 전달 받아 파일이 유효한 확장자인지 검사합니다.
- 이미지 파일을 미리보기 위해 사용할 수 있는 URL을 생성하고 반환합니다.
- 선택한 파일로 API 요청을 보내 업로드된 이미지의 URL을 반환받은 뒤에 반환합니다.
useModalControl | useAlertControl | useScrollBottom | useImageUploader |
---|---|---|---|
Post.jsx ChatRoomPage.jsx PostDetail.jsx ProfilePage.jsx |
Post.jsx ProductDetail.jsx AddProductPage.jsx PostDetail.jsx ProfileModificationPage.jsx ProfilePage.jsx ProfileSettingPage.jsx UploadPage.jsx |
FeedHomePage.jsx FollowListPage.jsx |
AddProductPage.jsx ProfileModificationPage.jsx ProfileSettingPage.jsx UploadPage.jsx |
axios 라이브러리 활용 settingAxios.jsx
- API 요청을 보낼 기본 틀의 URL과 header을 포함하고 있는 jsx 파일을 별도로 생성하고 재사용하도록 하여,
요청할 URL과 HTTP 메서드만으로 API 요청이 가능하게끔 했습니다. - 토큰이 필요한 API 요청의 경우 axios 라이브러리에서 제공하는 interceptors 를 이용해서
인증 헤더를 추가하여 인증된 요청을 보내도록 했습니다.
컴포넌트의 재사용성 고려 FollowListPage.jsx
/ UploadPage.jsx
/ AddProductPage.jsx
- useLocation Hook을 호출해서 생성한 객체의 속성인
pathname
으로 현재 페이지의 경로를 확인하고,
이를 조건문에 활용하여 컴포넌트를 재사용하도록 했습니다.
로그인 여부에 따른 페이지 접근 AtomUserState.js
/ ProtectedRoute.jsx
/ App.js
- Recoil의
Selector
와 React-router의<Outlet/>
,<Navigate>
컴포넌트를 이용해서
로그인 유무에 따라 특정 페이지에 접근 시 페이지를 보호하고 특정 페이지로 리다이렉팅 시키는 Protected Route를 생성했습니다.
![](https://private-user-images.githubusercontent.com/96939334/249054774-3d78f730-199b-43ac-8d9b-c364114c68ca.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4OTExNTAsIm5iZiI6MTcyMzg5MDg1MCwicGF0aCI6Ii85NjkzOTMzNC8yNDkwNTQ3NzQtM2Q3OGY3MzAtMTk5Yi00M2FjLThkOWItYzM2NDExNGM2OGNhLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MTclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODE3VDEwMzQxMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTQwMWFmMGY2NWRkNDY0NzQxN2NhNDY0OTY2OTM1NzJmNjk4YmRjNzBjNjBiN2RkYmI0OGZhNzQ1YzBiZmVkYzImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.PQSN0sR3MMnHTqfesYovCRMMk0F4uAIsIaodG-H3nig)
Recoil을 선택한 이유?
- Redux는 많은 추가적인 코드와 설정을 필요로 하지만 Recoil은 상대적으로 간단하고 직관적인 boilerplate-free API를 제공합니다.
- React 문법 친화적이고, 전역 상태 값도 React의 state처럼 간단한 get/set 인터페이스로 사용할 수 있는 API를 제공합니다.
- React를 배운 기간이 얼마 되지 않은 팀원끼리 협업 할 때 유용합니다.
- React가 제공하는 전역 상태관리 기능인 Context API 활용해서 상태 관리를 할 수 있지만 나중에 중간 규모, 대규모 프로젝트를 생각했을 때 프로젝트의 요구사항과 복잡성을 고려해서 recoil과 같은 상태 관리 라이브러리를 경험해볼 필요성이 있기 때문에 recoil로 상태관리를 하기로 결정했습니다.