Skip to content

pre-onboarding-frontend-7-team-3/pre-onboarding-7th-2-1-3-premigration

Repository files navigation

원티드 프리온보딩 프론트엔드 3팀 - Assignment #3

목적 : B2C 차량대여 서비스를 제공하는 웹 사이트 구축

프로젝트 기간 : 2022년 11월 1일 ~ 2022년 11월 4일


📖 목차


⌨️ 실행 방법

$ git clone https://github.com/pre-onboarding-frontend-7-team-3/pre-onboarding-7th-2-1-3.git
$ npm install
$ npm start

📃 협업 과정

본 프로젝트는 동료학습에 최적화된 과정을 찾아가며 진행했습니다. VSC Live Code extension을 활용해서 라이브 코드 리뷰를 진행하고 각자 구현한 코드에 대한 피드백 및 리팩토링 후 페어 프로그래밍 방식으로 Best Practice를 채택했습니다.

  1. VSC Live Share
  • 개발 초기에 업무를 최대한 작은 단위로 나눈 뒤 같이 프로그래밍하는 방식의 개발 프로세스를 선택했습니다. 단순 화면 공유 기능을 사용했을 때는 동시에 작업을 하거나 다양한 피드백을 주고 받기 어려웠으나 익스텐션을 사용해서 실시간으로 코드를 작성하고 디버깅할 수 있어서 개발 기간을 단축시켰습니다.

  1. husky를 이용해 commit전 lint 자동 검사

☑️ Best Practice 및 채택 근거

1. barrel 방식 / ~~~절대경로 지정 // 영훈님

  • 개발 효율성과 생산성 향상
  • barrel방식으로 폴더 구조를 구성하여 파일이름의 가독성 높이기
  • jsconfig.json에 baseUrl을 지정하여 import시 경로의 가독성 높이기

2. useReducer / useContext Hook

  • 본 프로젝트에서 상태 관리 라이브러리의 제한은 없었으나 내장 API를 사용해서 구현하자는 공통된 의견이 있어 useReducer와 useContext 훅을 채택했습니다. 컴포넌트 단에서 여러 상태를 만들기 보다 컨포넌트 간 상태 공유가 가능하고 비동기 요청에 대한 과정과 결과 상태를 한 영역에서 관리할 수 있는 장점에 의견을 모았습니다. 더 작은 영역에서 확실한 책임을 지도록 커스텀 reducer와 context prodiver 컴포넌트로 로직을 분리해서 관리했습니다.

참고 폴더 src/context

https://github.com/pre-onboarding-frontend-7-team-3/pre-onboarding-7th-2-1-3/blob/edbcce232e4fa90438532c6ff59a991e1c6a74ab/src/helpers/useCarReducer.js#L1-L16


3. Context API를 활용한 UI에 대한 정보와 데이터

  • 팀원들과 모바일 환경에서 원활한 사용자 경험에 대한 의견을 공유한 결과 차량 상세 페이지에서 뒤로 가기를 눌렀을 때 직전에 선택한 카테고리, 스크롤 위치 및 데이터가 출력되게 구현했습니다. 초기에는 기능 별로 사용될 상태를 컴포넌트 단에서 선언하고 관리했으나 context API를 채택해서 선택된 카테고리 상태, 네비게이션 ref에 대한 스크롤 위치 정보 및 차량 목록에 대한 데이터를 관리했습니다.

https://github.com/pre-onboarding-frontend-7-team-3/pre-onboarding-7th-2-1-3/blob/b084a35634c7679f0693aa6a451444e47d1cf427/src/context/NavContext.js#L1-L24


4. SEO - 카카오톡, 페이스북에 공유 시 아래의 내용이 미리보기로 노출

  • 초기 순수 CRA환경에서 벽을 맞이했습니다. react-hook을 통한 og태그 관련 DOM조작과 react-snap 라이브러리를 통한 pre-render를 사용해보았습니다. 비구글 검색엔진에 대하여 SEO crawlling은 가능하게 하였지만, 두 방법 모두 Open Graph에 동적 대응할 수 없었습니다. 추가 구현사항을 구현하기 위해서는 next.js로의 마이그레이션이 필요하다고 판단했습니다.
export const useMetaTegs = (TitleofMetaTegs) => {
  const [metaTegs, setMetaTegs] = useState(TitleofMetaTegs);
  const updateMetaTags = () => {
    document.querySelector('meta[property="og:description"]').setAttribute('content', TitleofMetaTegs);
    document.querySelector('meta[property="og:url"]').setAttribute('content', window.location.href);
  };

  useEffect(updateMetaTags, [metaTegs]);
  return setMetaTegs;
};

5. next.js 마이그레이션

  • Server Side Rendering, Automatic Routing, Automatic Code Splitting등의 장점을 가진 Next.js. SEO 관련 사항 중 Open Graph를 구현하기위해 마이그레이션을 진행했다.
  • 찾아보니 _App.js에서 SEO처리를 함을 확인했다. 다만, DefaultSEO를 사용하면 그 외의 페이지에서 NextSEO를 통한 동적 SEO의 구현이 먹통이 되는 경우가 발생한다. 이를 해결하기 위해 getStaticProps로 _App.js에 pageProps로 데이터를 넘기고 경우에 따라 적당한 SEO(open graph)가 들어갈 수 있도록 처리하였다.
// [id].jsx
export async function getStaticPaths() {
  return {
    paths: [],
    fallback: "blocking",
  };
}

export async function getStaticProps(context) {
  const { params } = context;

  const res = await fetch("https://preonboarding.platdev.net/api/cars", {
    method: "GET",
    headers: {
      "Content-type": "application/json",
    },
  }).then((res) => res.json());

  return {
    props: res.payload.filter((e) => {
      return e.id === Number(params.id);
    })[0],
  };
}
// _App.jsx
function MyApp({ Component, pageProps }) {
  const isEmptyObj = (obj) => {
    if (obj.constructor === Object && Object.keys(obj).length === 0) {
      return true;
    }
    return false;
  };

  return (
    <>
        { /* ... */ }
        
      {isEmptyObj(pageProps) ? (
        <DefaultSeo {...DEFAULT_SEO} />
      ) : (
        <SEO data={pageProps} />
      )}
      
        { /* ... */ }
    </>
  );
}

export default MyApp;

6. 반응형 모바일 웹


7. 상수 데이터의 활용

  • live share 중 UI 구성에 필요한 정적인 데이터가 하드 코딩 돼있어 가독성이 떨어진다는 의견을 공유했습니다. 반복문을 통해서 코드를 간결하게 정리할 수 있는 데이터는 상수화 처리를 했고 재상용성과 추후 유지보수를 고려해서 /constants 디렉토리에서 모두 관리 했습니다.

https://github.com/pre-onboarding-frontend-7-team-3/pre-onboarding-7th-2-1-3/blob/472394ea9883a7f3ed198bbb9e12c7c57fa3f6e9/src/components/CarDetail/CarDetail.jsx#L1-L49


🔒 팀 코드 컨벤션

  • git commit message 컨벤션
커밋명 내용
feat 파일, 폴더, 새로운 기능 추가
fix 버그 수정
docs 제품 코드 수정 없음
style 코드 형식, 정렬, 주석 등의 변경
refactor 코드 리팩토링
test 테스트 코드 추가
chore 환경설정, 빌드 업무, 패키지 매니저 설정등..
hotfix 치명적이거나 급한 버그 수정
  • branch 컨벤션
브랜치명 내용
develop 파일, 폴더, 새로운 기능 추가
fix 버그 수정
docs 제품 코드 수정 없음
refactor 코드 리팩토링
hotfix 치명적이거나 급한 버그 수정

🔨 사용 기술

HTML5 CSS3 JavaScript React NextJS

Axios styled-components react-responsive

Git GitHub Notion


📦 폴더 구조

📂 src
├── 📂 apis // 차량 리스트를 불러오는 api 관리
├── 📂 components // 컴포넌트 관리
│   ├── 📂 common // 재사용되는 컴포넌트 관리
│   │   ├── 📂 svgs // svg를 함수형으로 분리하여 관리
│   │   ├── 📄 BackButton // 뒤로 가기 버튼
│   │   ├── 📄 Button // props로 스타일을 받아 커스텀하여 사용할 수 있는 버튼
│   │   ├── 📄 Icon // props로 아이콘 이름을 받아 svg를 꺼내 사용할 수 있는 컴포넌트
│   │   ├── 📄 Loading // 데이터가 응답되기 전에 로딩중 텍스트를 보여주는 컴포넌트
│   │   └── 📄 NoData // 보여줄 데이터가 없을 때 텍스트를 보여주는 컴포넌트
│   ├── 📂 CarDetail // 차량 상세 페이지에 사용되는 컴포넌트
│   ├── 📂 CarListItem // 차량 리스트에 사용되는 하나의 차량 정보에 대한 컴포넌트
│   ├── 📂 CarList // 차량 리스트 컴포넌트
│   ├── 📂 Header // 페이지 제목을 나타내는 컴포넌트
│   └── 📂 Nav // 차량 카테고리 컴포넌트
├── 📂 constants // 상수 관리
├── 📂 context // context API 관리
│   ├── 📄 CarContext // 차량 정보 관련 Context
│   └── 📄 NavContext // 차량 카테고리 관련 Context
├── 📂 helpers // reducer 관리
│   └── 📄 useCarReducer
├── 📂 utils // 공통적으로 사용되는 util 함수 관리
│   ├── 📄 formatAttribute // api를 통해 제공받는 차량정보 한글로 변경
│   ├── 📄 CarInfoConverter // api를 통해 제공받는 차량정보 한글로 변경
│   ├── 📄 dateParse // api를 통해 제공받는 날짜정보 출력
│   └── 📄 isNewCar // 신규 차량인지 확인하는 함수
├── 📂 pages // 페이지 관리
│   ├── 📂 detail
│   │   └── 📄 [id].js
│   ├── 📄 _app
│   ├── 📄 _document
│   ├── 📄 _error
│   └── 📄 index
└── 📂 styles // global style 적용
    ├── 📄 GlobalStyle
    └── 📄 Theme

👨‍👩‍👧‍👦 팀원

조은지
(팀장)
고영훈
(서기)
김창희
(팀원)
박정민
(팀원)
Joeunji0119 YeonghunKO PiperChang ono212
Joeunji0119 YeonghunKO PiperChang ono212
문지원
(팀원)
이상민
(팀원)
이지원
(팀원)
조수진
(팀원)
moonkorea00 dltkdals224 365supprot suzz-in
moonkorea00 dltkdals224 365support suzz-in