ony540 / BangKKuseok

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

🏠 방꾸석 🐈



방꾸석에서 인테리어를 구경하며👀 운이 좋다면 구매까지🍀


React Recoil React-Router React-Query

Axios StyledComponents Eslint Prettier

GitHub Repo stars

Size Top Language


🗝️ 방꾸석 배포 링크 및 테스트 계정

👉 방꾸석 시작하기

ID: ohlee_official@bk.com
PW: 123123

📑 프로젝트 발표자료

👉 KeyNote | PPTX


📢 1. 서비스 소개

인테리어를 사랑하는 모든 이들을 위한 온라인 인테리어 플랫폼, 방꾸석을 소개합니다!

방꾸석은 대부분의 경제 활동을 집에서 해결하는 '홈코노미(Home + Economy)' 소비가 증가함에 따라 자리잡은 홈퍼니싱(Home + Furnishing) 트렌드에서 시작되었습니다.

인테리어 SNS 및 중고 거래 애플리케이션으로써 사용자들은 인테리어에 관심이 있는 사람들과 소통하고, 아이디어를 제공하며 자신만의 개성 있는 공간을 공유하고 인테리어 제품을 편리하게 거래할 수 있습니다.

비교적 거래가 어려운 인테리어 제품이 사용되는 공간을 판매하는 상품 태그와 함께 공유함으로써 구매자는 시각적으로 인테리어 아이디어를 얻어 쉽고 편리하게 자신만의 집을 꾸밀 수 있고, 판매자는 이를 통해 기존에 겪고 있던 판매에 대한 어려움을 해결할 수 있습니다.



🐈 2. 방꾸석 팀원 소개

안녕하세요, 저희는 멋쟁이사자처럼 14조 14불란 오리🐥입니다 !
오씨 성과 이씨 성을 가진 팀원 구성으로 오리(Oh!Lee)라는 팀명을 짓게 되었습니다 :)


✴️ 3. 역할 분담


📅 4. 개발 일정

🐥 2023.06.01 - 2023.06.30



⚙️ 5. 개발 환경 및 기술 스택

👉 API 명세 바로가기


왜 라이브러리를 사용했을까?


컨벤션

eslint

{
  "extends": ["react-app", "prettier"],
  "rules": {
    "indent": ["error", 2, { "SwitchCase": 1 }], // 들여쓰기 2칸만 허용
    "no-var": "error", // // var 키워드 사용 금지
    "require-await": "error", // async 함수 내부에 await 키워드가 없으면 오류 발생
    "eqeqeq": "warn", // ==, != 대신에 ===, !== 사용
    "react/prop-types": 0, // 프롭스 타입 무시
    "no-unused-vars": "off" // 호출되지 않은 변수도 사용 가능하게 설정
  }
}

prettier

{
  "bracketSpacing": true, // 객체 리터럴에서 괄호에 공백 삽입
  "jsxBracketSameLine": false, // JSX의 마지막 `>`를 다음 줄로 내릴지 여부
  "jsxSingleQuote": true, // JSX에 홑따옴표 사용 여부
  "singleQuote": true, // 홑따옴표 사용 여부
  "proseWrap": "preserve", // markdown 텍스트의 줄바꿈 방식 (v1.8.2)
  "semi": true, // 세미콜론 사용 여부
  "printWidth": 100, // 줄 바꿈 할 폭 길이
  "endOfLine": "auto", // EoF 방식, OS별로 처리 방식이 다름
  "useTabs": false, // 탭 사용 여부
  "tabWidth": 2, // 탭 너비
  "trailingComma": "all", // 여러 줄을 사용할 때, 후행 콤마 사용 방식
  "arrowParens": "always" // 화살표 함수 괄호 사용 여부
}

Github Issue Template


Github PR template


커밋 컨벤션

✨ feat: 기능 추가, 삭제, 변경
🐛 fix: 버그, 오류 수정
📝 docs: readme.md, json 파일 등 수정, 라이브러리 설치 (문서 관련, 코드 수정 없음)
🎨 style: CSS 등 사용자 UI 디자인 변경 (제품 코드 수정 발생, 코드 형식, 정렬 등의 변경)
♻️ refactor: 코드 리팩토링
🧪 test: 테스트 코드 추가, 삭제, 변경 등 (코드 수정 없음, 테스트 코드에 관련된 모든 변경에 해당)
⚙️ config: npm 모듈 설치 등
🌱 chore: 패키지 매니저 설정할 경우, etc 등 (ex. gitignore)
💬 comment:	필요한 주석 추가 및 변경
🚚 rename:	파일 또는 폴더 명을 수정하거나 옮기는 작업만인 경우
🚚 remove:	파일을 삭제하는 작업만 수행한 경우

Styled Components 컨벤션

wrapper: ~Wrapper
ex) HeaderWrapper, NavbarWrapper

wrapper가 필요없는 이름과 스타일드 컴포넌트 이름이 같을 경우: Styled~
ex) StyledInput, StyledButton

div태그: ~Box
ex) InfoBox, ContentBox

4. section태그: ~Section
ex) InfoSection, ContentSection

5. ul태그: ~List
ex) InfoList, ContentList

6. li태그: ~Item
ex) InfoItem, ContentItem

중첩은 최대 2단계까지만
ex - list { li{ a{} } }까지

li내에 스타일할 요소가 3개이상이면 li를 Item으로 빼기


📂 6. 프로젝트 폴더 구조

🏠 bangkkuseok
├─ .github
│  ├─ ISSUE_TEMPLATE  ─────────────── 📜 이슈 템플릿
│  └─ PULL_REQUEST_TEMPLATE.md ────── 📜 PR 템플릿
│─ .gitignore
│─ .gitmessage   ──────────────────── 📜 커밋 템플릿
│─ .prettierignore
│─ .prettierrc   ──────────────────── ⚙️ prettier 설정 파일
│─ .eslintrc     ──────────────────── ⚙️ eslint 설정 파일
├─ public
│  ├─ favicon.ico
│  └─ index.html
└─ 📂 src
  ├─ 📂 api     ───────────────────── 📲 Axios 인스턴스 및 API 관련 모듈 함수
  ├─ 📂 assets  ───────────────────── 🧸 폰트, 이미지 등 정적 리소스
  ├─ 📂 atoms ─────────────────────── ✨ 리코일 관련 폴더
  ├─ 📂 components
  │  ├─ 📂 common ─────────────────── 📦 공통 컴포넌트
  │  ├─ 📂 LoginSignUp ────────────── 📦 로그인, 회원가입 페이지에서 사용되는 컴포넌트
  │  ├─ 📂 PostDetail  ────────────── 📦 게시글 상세 페이지에서 사용되는 컴포넌트
  │  ├─ 📂 PostEdit   ─────────────── 📦 게시글 수정 페이지에서 사용되는 컴포넌
  │  ├─ 📂 PostUpload   ───────────── 📦 게시글 업로드 페이지에서 사용되는 컴포넌트
  │  ├─ 📂 Product   ──────────────── 📦 상품 관련 페이지에서 사용되는 컴포넌트
  │  └─ 📂 Profile   ──────────────── 📦 프로필 관련 페이지에서 사용되는 컴포넌트
  ├─ 📂 constants   ───────────────── 🎈 공통적으로 사용되는 상수
  │  ├─ common.js
  │  └─ validate.js
  ├─ 📂 hooks ─────────────────────── ♻️ 커스텀 훅 폴더
  │  ├─ useDebounce.js
  │  ├─ useInputs.js
  │  └─ useObserver.js
  ├─ App.js
  ├─ index.js
  ├─ 📂 layout   ──────────────────── 🪅 공통으로 사용되는 레이아웃
  ├─ 📂 mock   ────────────────────── 🧸 mock 데이터 폴더
  ├─ 📂 pages   ───────────────────── 📲 라우팅이 적용된 주로 API를 요청하는 페이지 폴더
  ├─ 📂 styles   ──────────────────── 💄 전역으로 적용할 css 파일들이 포함된 폴더
  │  ├─ fonts.css
  │  ├─ GlobalStyle.js
  │  └─ theme.js
  └─ 📂 utils    ──────────────────── 🧸 공통으로 사용되는 유틸 함수
     ├─ filterPosts.js
     └─ getTime.js

✴️ 7. Git Branch 전략 - Github Flow


🤗 8. 방꾸석에서는 이렇게 협업해요

코드리뷰

  • VS code 라이브 쉐어
    • 실시간으로 팀원들과 원격으로 코드를 수정하고 편리한 트러블 슈팅을 경험했다.
    • 다양한 OS에서 사용이 가능하여 팀원들의 서로 다른 OS 차이에 구애받지 않았다.
  • PR 병합 규칙에 승인을 1회 이상으로 설정하여 PR을 무조건 확인할 수 있게 했다. 충돌을 방지하는 것과 더불어 팀원들의 코드에 리뷰를 달아주기 편리했다.

협업툴

  • 노션 : 정보 공유, 회의록, 요구 사항 정리 및 컨벤션 정리
    • 다양한 형식과 템플릿이 공유되어 있고, 디자인적으로 깔끔하고 시각적인 정보를 제공하여 작업 상태를 한 눈에 파악할 수 있었다.
    • 실시간 공동 작업을 할 수 있었다.
  • 피그마 : 디자인 공동 작업을 할 수 있었다.
  • 커밋 컨벤션 : 협업을 하다 보면 복합적인 커밋 내용이 많아지기 때문에 커밋 컨벤션을 지정하여 커밋 목적을 쉽게 볼 수 있게 했다. 지정 작업자가 아니더라도 코드 변경에 대한 문맥을 파악하기 쉽고 이력 추적을 효과적으로 할 수 있었다.

소통

  • 디스코드로 주 5~6회 회의를 진행하여 한 달간 22회의 회의를 진행했다. 오류 발생시 즉각적인 피드백과 문제해결이 가능했다.


✴️ 9. 주요 기능 소개

1) 홈

시작 화면 회원가입 페이지 프로필 설정 페이지
splash 회원가입 프로필
로그인 페이지 피드 페이지 검색 페이지
로그인 피드 검색

2) 채팅

채팅 목록, 채팅방 페이지 404페이지
채팅 목록, 채팅방 페이지

3) 게시글

게시글 상세 페이지 게시글 작성 페이지 게시글 수정 페이지
게시물수정
게시글 삭제 게시글 신고 좋아요, 댓글 기능
최종_게시글삭제_AdobeExpress

4) 프로필

프로필 페이지 프로필 수정 페이지
ᄆ프로필 프로필 수정
팔로워/팔로잉 페이지 로그아웃 기능
팔로우페이지 로그아웃

5) 판매 상품

상품 등록 페이지 상품 수정 페이지 상품 삭제 페이지
상품 등록 및 판매 사이트 이동 상품 수정 상품 삭제

✴️ 10. 상세 담당 업무

🖤 공통

  • 컨벤션 지정
    • 커밋 메시지 컨벤션, 코드 컨벤션, 네이밍 컨벤션, 디렉토리 구조, Styled-Components 컨벤션
  • 프로젝트 관리
    • 이슈 관리
    • 이슈 진행 상황 관리
    • 버그 관리
    • 요구사항 문서 작성

🖤 나영

🎨 디자인

  • 전반적 UI 디자인 전체
  • 발표 자료 제작

🖥️ 화면 개발

  • 탭 메뉴, 게시글 카드, 상품 카드, 인풋, 이미지 업로드 공통 컴포넌트 제작
  • Splash, 메인, 피드, 게시글 상세, 게시글 등록 및 수정, 404 페이지 퍼블리싱

⚡ 기능 개발

  • 공통 컴포넌트
    • PostCard, ProductCard
    • RoundedInput, RoundedButtomInput
    • Tabs
    • ImageUpload
  • 게시글 등록 페이지
    • step을 나누어 단계별 행동을 유도하여 사용자 경험 개선
    • 이미지에 판매하는 상품을 태그할 수 있는 기능 구현
  • 게시글 상세 페이지
    • 게시글 삭제, 신고 기능 구현
    • 댓글 작성, 삭제, 신고 기능 구현
  • 게시글 수정 페이지
    • 게시글 수정 기능 구현
  • 피드 페이지
    • 무한 스크롤 기능 구현
    • 게시글 좋아요 기능 구현
  • 메인 페이지
    • three.js를 사용한 3D 인터랙션 요소 추가
  • 로딩 페이지
    • 회원가입 후 로그인 페이지로 이동하는 로딩페이지

🖤 지원

🖥️ 화면 개발

  • 헤더, 네브바, Confirm, 프로필 카드 공통 컴포넌트 제작
  • 홈 페이지, 검색 페이지

⚡ 기능 개발

  • 홈페이지
    • 피드
      • 모든 데이터 중 방꾸석 데이터만 필터링하여 피드 로드
      • 로딩 속도를 개선하기 위해 전체 데이터를 모두 불러온 후 필터링하는 것이 아닌 useInfiniteQuery를 사용하여 데이터를 100개씩 불러올 때마다 필터링
    • 캐러셀 기능 구현
      • 팔로우한 계정의 피드 중 좋아요가 많은 순으로 5개 정렬
      • 팔로우한 계정이 없다면 mock 데이터 표시
    • SpaceTabs 기능 구현
      • 스크롤 없이 옆으로 스크롤할 수 있는 스와이프 기능 구현
  • 검색 페이지
    • API의 Username을 필터링 하여 검색 기능 구현
    • 로딩 중 Skeleton UI를 보여줘 사용자 경험 개선
    • 검색이 끝난 후 검색 리스트를 보여주기 위해 useDebounce Hooks를 만들어 사용자 경험 개선
    • 최근 검색 기록을 LocalStorage에 저장하여 최근 검색 표시
    • 검색 결과 더보기 기능 구현

🖤 미현

📜 프로젝트 총괄 및 문서화

  • 커뮤니케이션
    • 프로젝트 기간 동안 총 22회의 회의를 열어 진행 상황과 목표를 지속적으로 공유함으로써 팀워크를 강화
  • 프로젝트 관리
    • 브랜치 관리
    • Netlify를 이용한 프로젝트 배포
  • 프로젝트 진행을 위한 작업
    • GitHub 이슈 템플릿, PR 템플릿 등록
    • 프로젝트 초기 세팅 작업 - 폴더 트리 구성 - ESLint & Prettier 설정 및 적용 - 글로벌 스타일 적용
    • 라우터 설계 및 구축
  • 문서화
  • 지식 공유
    • 노션에 스터디 정보 공유 페이지를 만들어 팀원 간 이슈 해결 및 공부한 부분 공유하는 문화 전파

🖥️ 화면 개발

  • 캐러셀, 기본 버튼 및 소셜 버튼, Toast, 공통 레이아웃 컴포넌트 제작
  • 프로필 및 수정 페이지, 팔로우/팔로잉 페이지, 상품 모달 및 수정 페이지 퍼블리싱

⚡ 기능 개발

  • 프로필 관련 기능 구현
    • 로그인시 생성되는 토큰 값을 가지고 프로필 정보 로드
    • 페이지 url에 따라 유저 프로필과 내 프로필 분리하여 로드
    • 프로필 수정 기능 구현 - 프로필을 수정할 때 accountname 변경에 따른 프로필 정보를 불러오기 위해 캐시된 이전 데이터를 삭제해주는 react query의 QueryClient removeQueries 메서드 사용
  • 로그아웃 기능 구현
    • 로컬 스토리지에 저장된 토큰 및 최근 검색 기록 삭제
  • 상품 관련 기능 구현
    • 상품 추가 기능 구현 - 상품 추가시 useInputs Hooks을 통해 validate 체크와 입력 값을 저장
    • 상품 삭제 기능 구현
  • 팔로우 기능 구현
    • 팔로우, 팔로잉 리스트에 무한 스크롤링 적용
    • 팔로우, 언팔로우를 서버에 요청하고 화면에 바로 적용하기 위해 이전 쿼리를 유효하지 않은 상태로 만들어 리패치 하기 위한 react query의 QueryClient invalidQueries 메서드 사용
  • Toast 메시지 구현
    • react-toastify 라이브러리를 추가하여 삭제, 신고시 toast 메시지 적용

♻️ 컴포넌트 리팩토링 및 중복 제거

🖤 보은

🖥️ 화면 개발

  • 공통 컴포넌트 UI
    • Input
    • BottomSheet의 BasicModal과 ListModal
    • 갤러리
  • 메인, 로그인, 회원가입, 채팅(채팅 리스트, 채팅룸) 페이지 UI

⚡ 기능 개발

  • 메인 페이지
    • 이메일로 로그인 / 회원가입을 누르면 해당 페이지로 이동하는 기능 구현
  • 로그인 페이지
    • 이메일 + 비밀번호를 입력하고 가입된 이메일인지 검사를 진행하는 기능 구현
  • 회원가입 페이지
    • 이메일 + 비밀번호를 입력하고 유효성 검사를 진행하는 기능 구현
    • 프로필 설정에서 이름, 아이디, 소개, 프로필 사진을 입력하고 유효성 검사를 진행하는 기능 구현
  • 채팅 페이지(Mock data 이용)
    • 채팅 리스트 : 나에게 메시지를 보낸 사람의 프로필 사진, 이름, 채팅 한 줄 요약과 보낸 날짜가 뜨고 클릭하면 채팅룸으로 이동하는 기능 구현
    • 채팅 룸 : 이미지 또는 텍스트 메시지를 보낼 수 있고, 채팅이 컨테이너 요소를 벗어나게 되면 최신 채팅이 위로 뜨도록 기능 구현
  • Authenticated 페이지
    • url에서 주소를 직접 입력했을 경우, 로그인 상태일때와 로그아웃 상태일때 각각 url 접근을 방지하였다.


✴️ 11. 핵심 코드

11-(1) 주어진 API에서 데이터 필터링하기
  • 주어진 api를 그대로 사용해서는 모든 데이터 중 방꾸석의 데이터만 불러올 수 없었습니다. 따라서 content의 “space”, “keyword”를 추가하여 이들이 포함된 데이터만 필터링하여 모든 데이터를 보여주었습니다.
content: '{"space":"침실","detail":"쉬폰 패브릭으로 침실의 분위기를 바꿀 수도 있답니다!"}’
itemName: '{"name":"노란색 스탠드","keyword”:"조명"}’

  • 또한 약 6000개의 모든 데이터를 불러온 후 필터링하면 화면을 보여주기까지의 속도가 매우 느려지기 때문에 useInfiniteQuery를 사용하여 limit를 100으로 설정하여 데이터를 100개씩 불러와 필터링하는 방식으로 구현하여 로딩 속도를 개선했습니다.
    ✨ feat: 홈페이지 전체 목록 로딩 속도 줄이기
const {
  data: homePostData,
  isLoading: homeIsLoading,
  fetchNextPage: homeFetchNextPage,
} = useInfiniteQuery(
  'homePostData',
  ({ skip = count.current }) => getAllPost({ limit: 100, skip }),
  {
    getNextPageParam: (lastPage) => {
      return lastPage.nextPage + 1;
    },
    onSuccess: (newData) => {
      const pageParam = newData.pageParams.length - 1;
      setAllPosts([...newData.pages[pageParam].data]);
      if (newData.pages[pageParam].isLast) {
        setIsLast(true);
      }

      const allFiltered = allPosts.filter((post) => post.content?.includes('"space"'));
      setFilteredAllPosts((prevData) => [...prevData, ...allFiltered]);
    },
  },
);

useEffect(() => {
  if (!isLast) {
    homeFetchNextPage();
    count.current += 100;
  }
}, [homePostData, homeIsLoading, isLast, homeFetchNextPage]);
11-(2) STEP을 사용한 게시글 업로드 과정

PostUploadPage 컴포넌트는 useState 훅을 활용하여 ‘사진 선택’, ‘상품태그 추가’, ‘게시글 작성’과 같은 업로드 단계를 관리합니다. 현재 step에 따라 해당하는 레이아웃을 렌더링하여 사용자가 단계별로 한 페이지에 한 가지 행동만 하도록 유도하여 사용자 경험을 개선했습니다.

export default function PostUploadPage() {
//게시글 업로드 단계 : 사진 선택 / 상품태그 추가 / 게시글 작성
const [step, setStep] = useState('사진 선택');
const resetSelectedItems = useResetRecoilState(selectedProductsAtom);
const resetMouseLoc = useResetRecoilState(mouseLocAtom);
const resetBubbleLoc = useResetRecoilState(bubbleLocAtom);
....

const StepLayout = {
    '사진 선택': (
      <PostImgUpload setImg={setPostImg} setIsBtnActive={setIsBtnActive} postedImg={postedImg} />
    ),
    '상품태그 추가': <PostProductTag postedImg={postedImg} setIsBtnActive={setIsBtnActive} />,
    '게시글 작성': (
      <PostTextWrite
        postedImg={postedImg}
        setIsBtnActive={setIsBtnActive}
        setContent={setContent}
      />
    ),
  };

  return (
    <BasicLayout type='imageSelect'>
      <>
        {step === '사진 선택' && StepLayout[step]}
        {step === '상품태그 추가' && postedImg && StepLayout[step]}
        {step === '게시글 작성' && postedImg && StepLayout[step]}
      </>
    </BasicLayout>
  );
}
11-(3) 이미지 위의 원하는 위치에 상품 태그하기
  1. 태깅 단계: tagStep 상태 변수는 ‘클릭 유도’, ‘상품목록 확인’, ‘상품태그 추가’와 같은 태깅 프로세스의 다양한 단계를 관리합니다.

  2. 마우스와 말풍선 위치: atom을 사용하여 mouseLocbubbleLoc 상태 변수를 관리합니다. mouseLoc는 이미지 위의 태그 위치, bubbleLoc는 태그와 연결된 말풍선 위치를 나타냅니다.

  3. 이미지 클릭 처리: handleClickImg 함수는 태깅 단계에 대한 로직을 처리하고, 이미지에 대한 태그 위치를 계산합니다. 태그 위치에 따라 bubbleLoc 상태 값을 조정하여 말풍선이 이미지 위에 올바르게 배치되도록 합니다.

  4. 선택된 상품과 사용자 상품: 해당 컴포넌트는 selectedProductsAtomuserProductsAtom 값에 따라 바뀌는 모달에 뜰 목록을 Recoil의 selector를 사용하여 canSelectProductsSelector 선택할 수 있는 상품을 가져옵니다.

// PostProductTag.jsx

export default function PostProductTag({ postedImg, setIsBtnActive }) {
  //태그추가 단계 : 클릭 유도 / 상품목록 확인 / 태그와 버블 / 상품태그 추가
  const [tagStep, setTagStep] = useState('클릭 유도');
  //마우스, 말풍선 위칫값
  const [mouseLoc, setMouseLoc] = useRecoilState(mouseLocAtom);
  const setBubbleLoc = useSetRecoilState(bubbleLocAtom);
  //선택된 데이터
  const selectedItems = useRecoilValue(selectedProductsAtom);
  const userItems = useRecoilValue(userProductsAtom)

  //이미지 위 클릭하면
  const handleClickImg = (e) => {
    //1.'클릭 유도'일때
    if ((tagStep === '클릭 유도' || tagStep === '상품태그 추가') && e.target === e.currentTarget) {
      // 마우스 위치 지정
      const x = Math.floor((e.nativeEvent.offsetX / e.currentTarget.offsetWidth) * 100);
      const y = Math.floor((e.nativeEvent.offsetY / e.currentTarget.offsetWidth) * 100);
      setMouseLoc({
        x: x < 6 ? 6 : x > 94 ? 94 : x,
        y: y < 5 ? 5 : y > 95 ? 95 : y,
      });
		...
  };

  //마우스 위치에 따른 말풍선 위치
  useEffect(() => {
    ...
    setBubbleLoc({
      x: mouseLoc.x < 33 ? 33 : mouseLoc.x > 67 ? 67 : mouseLoc.x,
      y: mouseLoc.y > 28 ? mouseLoc.y - 7 : mouseLoc.y + 27,
      bubbleUp: mouseLoc.y > 28,
      edgeLeft: eLeft,
    });
  }, [mouseLoc, setBubbleLoc]);

...

return (
    <>
			...
      </PostProductTagWrapper>
      {tagStep === '상품목록 확인' && (
        <BottomSheet isShow={isShow} onClick={handleClickModalOpen}>
            <ModalProductList
              setIsShow={setIsShow}
              setTagStep={setTagStep}
              setIsBubbleShow={setIsBubbleShow}
            />
        </BottomSheet>
      )}
    </>
  );
}
// atoms/post.js

import { atom, selector } from 'recoil';

export const userProductsAtom = atom({
  key: 'userProductsAtom',
  default: [],
});

export const selectedProductsAtom = atom({
  key: 'selectedProductsAtom',
  default: [],
});

export const canSelectProductSelector = selector({
  key: 'canSelectProductsSelector',
  get: ({ get }) => {
    const list = get(userProductsAtom);
    const filter = get(selectedProductsAtom).map((product) => product.id);
    return list.filter((product) => !filter.includes(product.id));
  },
});
11-(4) 커스텀 훅

useInputs.js

  • input에 입력해야하는 값에 따라 입력 값을 저장하는 함수, 포커스를 잃었을 때 validate를 체크하여 에러 메시지를 설정하는 함수가 필요했습니다.
  • 따라서 useInputs 커스텀 훅을 만들어 중복으로 작성될 코드를 방지하였습니다.

useObserver.js

  • Intersection observer는 브라우저의 뷰포트와 타겟으로 설정한 요소를 관찰하여 뷰포트에서 요소의 포함 여부를 구별하는 기능을 제공합니다.
  • 비동기적으로 실행되기 때문에 scroll과 같은 이벤트 기반의 요소 관찰에서 발생하는 렌더링 성능이나 이벤트 연속 호출 같은 문제 없이 사용이 가능합니다.

useDebounce.js

유저를 검색하기 위해 input에 텍스트를 입력할 때마다 검색 결과가 바뀌면 사용자 입장에서 보기 불편하고 비효율적일 수 있습니다. 따라서 연속된 이벤트가 발생할 때 일정 시간동안 마지막 이벤트만 처리하도록 하는 useDebounce 커스텀 훅을 생성하여 입력값이 일정 시간동안 변화가 없을 때에만 검색 요청을 처리하도록 하였습니다.


✴️ 12. 트러블 슈팅

11-(1) 주어진 API에 따른 다른 서비스 유저 예외처리

♻️ refactor: 다른 서비스 사용자 경우 게시글 및 상품 예외 처리

주어진 서비스 api를 다른 서비스와 공유하고 있어, 다른 이용자도 검색되고 팔로우되는 문제가 발생하여, 해당 유저의 프로필에 들어가게될 경우 해당 게시글에는 에러가 발생했습니다. 이를 해결해주기 위해 게시글에 space값이 없을 경우, 상품에 keyword가 없는 경우에 대한 예외처리를 진행했습니다. 또한 서비스마다 이미지를 받는 형식에 차이가 있어 대부분의 경우를 고려한 예외처리를 하고, 이미지에 오류가 있을 경우 기본이미지로 대체하였습니다.

11-(2) QueryClient Invalide Query 적용하기.
  • 기존에 팔로우 요청을 보내면, 팔로우 요청은 성공하지만 기존 데이터가 그대로 캐시되어있어 새로고침을 해야만 팔로우 리스트를 다시 불러와 반영되는 문제가 발생했습니다
// 기존 코드
// 팔로우
const postFollowMutation = useMutation(postFollow, {
  onSuccess: () => {
    queryClient.invalidateQueries('followers');
  },
  onError: () => {
    console.error('팔로우 실패');
  },
});
  • 🪄 해결 방법: react query의 Query Client에서 invalidateQueries()를 사용하여 기존에 조회했던 쿼리를 무효화시키고 데이터를 새로 조회해올 수 있다.
// 팔로우
const postFollowMutation = useMutation(postFollow, {
  onSuccess: () => {
    queryClient.invalidateQueries('followers');
  },
  onError: () => {
    console.error('팔로우 실패');
  },
});


✴️ 13. 리팩토링할 부분

  • Portal을 활용한 Modal 리팩토링
  • 웹 접근성 높이기
  • 이미지 압축 및 예외처리
  • 완전 반응형 적용하기
  • 스크롤 위치 기억시키기
  • 날씨 API를 사용하여 청소하기 좋은 날 추천
  • 채팅기능 구현


✴️ 14. 느낀점

🧸 이미현

노션에 처음 자기소개를 작성하고, 회고조와 만나 서먹서먹했던 때가 아직도 엊그제 같은데 벌써 4개월이라는 시간이 지나 멋사 팀 프로젝트 발표날이 왔다는게 아직도 믿겨지지 않습니다ㅎㅎ 제대로 팀 프로젝트를 해본 건 이번이 처음이라 깃을 다루면서 땀도 많이 흘리고 오류도 물론 많이 마주치게 됐습니다..ㅎㅎ 부족한 저였음에도 항상 좋은 반응을 해주고, 도움도 마다하지 않고 따라와주신 오리분들께 감사하단 말씀을 드리고 싶습니다! 덕분에 우리가 처음 목표했던 다양한 라이브러리의 사용, 협업 경험, 그리고 잘 마무리하는 방법까지 차곡차곡 쌓아서 또 하나의 기억 조각을 만들 수 있었습니다. 목표했던 것을 달성한 이번 경험을 토대로 앞으로의 목표들도 자신감 있게 '할 수 있다'는 마음을 가지고 나아갈 수 있길 바래요! 팀 외에도 도움을 준 멘토님, 강사님, 매니저님, 멋사 5기 어려분들도 너무 감사하고, 수고많으셨습니다. 추후 있을 리팩토링에서 다시 만나요 var var🖐️🖐️

🍙 오지원

처음 접해본 리액트로 진행하는 팀프로젝트라 처음엔 걱정이 되기도 했지만 좋은 팀원분들을 만나 이렇게 잘 마무리할 수 있었던 것 같습니다. 컨벤션을 정하고, 깃, 깃이슈, pr을 사용하여 조금 더 체계적으로 프로젝트를 진행하는 경험을 해본 것이 좋았고 무엇보다 선릉과 광화문을 팀원분들이랑 다니면서 만나서 함께 프로젝트를 진행했던 점이 좋았습니다. 맨날 모르는 것 투성이라 팀원분들을 많이 괴롭혔지만 옆에서 항상 많이 도와주시고 응원해주신 팀원분들 너무 감사하고 수고 많으셨습니다!

🥰 이보은

깃헙으로 협업하는 것도 처음이었고 리액트로 프로젝트를 진행하는 것도 처음이었습니다. 초반에 깃헙 실수도 많이 했지만, 조원분들께 바로 도움을 요청하였고, 그에 대한 조원분들의 조언으로 전에는 사용할 생각을 하지 않았었던 깃헙 데스크탑을 깔았습니다. 결과적으로 정말 편하게 작업할 수 있었고, 이후 실수의 빈도가 점점 줄어드는 모습을 볼 수 있었습니다. 혼자서 했다면 끝내지 못했을텐데 조원분들, 그 외에 도움주신 분들의 도움으로 끝까지 잘 마치고 성장할 수 있었다고 생각합니다. 모두 감사합니다

🍊오나영

혼자서는 하지 못할 깃, 컨벤션, 소통 등에 대해 배울 수 있었던 팀 프로젝트였습니다. 문제가 생겼을 때는 혼자서만 끙끙대기보다는 멘토님이나 조원들에게 서로 물어보며 더 나은 코드를 고민하고 개선하는 경험을 하여 뿌듯했고, 협업하는 방법과 태도에 대해 다시 한번 생각해보는 계기가 되었습니다. 또한 이번 프로젝트에서 recoil, react-query, threejs 등을 처음 사용하게 되었는데, 하기 전부터 겁먹지말고 시도해보는게 중요하다는걸 깨달았습니다. 이번 프로젝트를 통해 하드스킬도, 소프트스킬도 많이 성장했다고 느꼈습니다. 열심히 가르쳐주시고 함께 공부해주신 분들 모두 감사합니다!


About


Languages

Language:JavaScript 99.0%Language:CSS 0.6%Language:HTML 0.4%