-
원티드 프리온보딩 프론트엔드 코스 6기 3-1 과제(띵스플로우)
-
과제 목표 : 특정 깃헙 레파지토리의 이슈 목록과 상세 내용을 확인하는 웹 사이트 구축
-
수행 기간 : 2022/09/13 ~ 2022/09/15
이름 | 역할 |
---|---|
김리후 | Context API, 배포 |
이경준 | 이슈 상세 페이지 |
이혜성 | 팀장 / 초기 셋팅, 로딩표시, 인피니트 |
문선화 | UI 및 에러화면 |
홍성준 | 메인 페이지 |
-
React, JavaScript, TypeScript
-
Styled-components
-
Axios, Context API, Remark-gfm, React-markdown
- Install
$ yarn install
-
set environment variables
-
package.json과 같은 디렉토리에 .env.local 파일을 생성합니다.
-
.env.local 파일 안에 아래와 같이 작성합니다.
-
REACT_APP_API_HOST=https://api.github.com/repos/angular/angular-cli/issues
- start the project
$ yarn start
프로젝트 구조
📦src
┣ 📂components
┃ ┣ 📂text
┃ ┃ ┣ 📜index.tsx
┃ ┃ ┗ 📜styles.ts
┃ ┣ 📜Header.tsx
┃ ┣ 📜Layout.tsx
┃ ┣ 📜NotFound.tsx
┃ ┗ 📜Spinner.tsx
┣ 📂hooks
┃ ┗ 📜useIntersect.ts
┣ 📂pages
┃ ┣ 📂detail
┃ ┃ ┣ 📂components
┃ ┃ ┃ ┗ 📜common.ts
┃ ┃ ┗ 📜Detail.tsx
┃ ┗ 📂home
┃ ┃ ┣ 📂components
┃ ┃ ┃ ┣ 📜AdBanner.tsx
┃ ┃ ┃ ┗ 📜MainList.tsx
┃ ┃ ┗ 📜Home.tsx
┣ 📂store
┃ ┗ 📜api-context.tsx
┣ 📂styles
┃ ┣ 📂colors
┃ ┃ ┗ 📜index.ts
┃ ┣ 📂font
┃ ┃ ┗ 📜index.ts
┃ ┣ 📂typography
┃ ┃ ┣ 📜font-size.ts
┃ ┃ ┣ 📜font-weight.ts
┃ ┃ ┣ 📜get-line-clamp-css.ts
┃ ┃ ┣ 📜index.ts
┃ ┃ ┗ 📜text-decoration-css.ts
┃ ┗ 📜index.ts
┣ 📂types
┃ ┗ 📜index.ts
┣ 📂utils
┃ ┣ 📜FormatDate.ts
┃ ┗ 📜GetNextPage.ts
┣ 📜App.tsx
┣ 📜index.css
┣ 📜index.tsx
┗ 📜react-app-env.d.ts
-
/
: 메인페이지 -
/issue/:issueNumber
: 상세페이지
- 필수 사항
- 이슈 목록 및 상세 화면 기능 구현
- Context API를 활용한 API 연동
- 지정된 조건(open 상태, 코멘트 많은 순)에 맞게 데이터 요청 및 표시
- 데이터 요청 중 로딩 표시
- UI는 데스크톱, 모바일에서 보았을 때 모두 읽기 편하게 구현
- 선택 사항
- 에러 화면 구현
- CSS-in-JS 구현
-
이슈 목록 화면
- 이슈 목록 가져오기 API 활용
- open 상태의 이슈 중 코멘트가 많은 순으로 정렬
- 각 행에는 ‘이슈번호, 이슈제목, 작성자, 작성일, 코멘트수’를 표시
- 다섯번째 셀에는 광고 이미지 출력, 광고 이미지 클릭 시 https://thingsflow.com/ko/home로 이동
- 화면을 아래로 스크롤 할 시 이슈 목록 추가 로딩(인피니티 스크롤)
-
이슈 상세 화면
- 이슈의 상세 내용 표시
- ‘이슈번호, 이슈제목, 작성자, 작성일, 코멘트 수, 작성자 프로필 이미지, 본문' 표시
-
공통 헤더
- 두 페이지는 공통 헤더를 공유합니다.
- 헤더에는 Organization Name / Repository Name이 표시됩니다.
- 구현한 내용
-
인피니트 스크롤:
- Intersection Observer API를 이용한 useIntersect 훅 구현, ref를 반환함.
- 이슈목록을 보여주는 메인페이지에서 임의의 Target div에 ref 사용
- onIntersect 핸들러로 다음페이지 호출
- 다음페이지 호출때 클로져를 이용한 getNextPage() 함수 사용
- 마지막 페이지 예외처리
-
로딩표시:
- Spinner 컴포넌트 구현
- 인피니트 스크롤 로딩시 Spinner 표시
-
- 고민했던 내용
- 인피니트 스크롤때 다음 두 페이지를 fetching하는 버그가 있었음.
{!isLoading && <Target ref={ref} />}
위처럼 Target을 loading중이 아닐때만 렌더링하여 해결 (@성준님 솔루션)
- 구현한 내용
- 메인리스트페이지 렌더링, 5번쨰 셀 광고추가
- 고민했던 내용
- '5번째 셀마다 광고추가'가 선행인줄 알고 구현 후 변경하였다.
- 그로 인해 내부 페이지의 컴포넌트를 나눠 main page내에서 얼만큼 보여줘야 하나 생각.
- 추가로 개발 완료 후 context api는 개발/프로덕션용 api 설정을 했어야 했나 싶다.
- 구현한 내용
- 이슈 상세정보 렌더링
- 고민했던 내용
- response json value에 대한 타이핑, 추상화
- 이슈 상세 내용에 대한 json value를 타이핑(vscode extendsion 이용) 하다가 서버에서 내려주는 json value를 class 추상화해 사용하면 어떨까 하고 고민해보았다.
그러나 재가공이 필요할만한 필드값은 created_at, updated_at 정도 였고 조금은 이른 추상화가 아닌가 싶어 제거 하였다.const {data} = await fetch(...) setIssue(() => new Issue(data)) class Issue ...{ ... getCreatedTime( return this.... ) }
- response json value에 대한 타이핑, 추상화
- 구현한 내용
- Context API를 활용하여 공통으로 사용하게 될 api 로직 및 기본 state 값 구현
- 공통 type 지정
- 고민했던 내용
-
다른 컴포넌트에서 사용하게 될 공통 로직이 어떤 것일까 고민.
-
axios instance를 별도의 api 폴더에 구현하려 하였으나, 한 곳에 관심사를 모으기 위해 context api 내부로 이동.
-
활용하기 쉽게 api 요청을 아래와 같이 객체로 묶었으나, 결과적으로
getIssueDetailApi
는 사용되지 않을 것이라 판단하여 삭제.const api = { getIssueApi: (config?: AxiosRequestConfig) => axiosInstance.get(`${BASE_URL}`, config).then((response) => response.data), getIssueDetailApi: (issueNumber: number) => axiosInstance.get(`${BASE_URL}/${issueNumber}`).then((response) => response.data), };
-
- 구현한 내용
- 공통 UI 컴포넌트 구현 (Layout, Header)
- NotFound 에러 화면 구현
- 고민했던 내용
- 페이지가 2개 뿐이라 Header 컴포넌트 외에 공통으로 사용할 컴포넌트가 있을지 고민.
- 에러 화면의 경우 처음에 404 페이지만 생각하고 작업했는데 팀원분들을 통해 에러 경계라는 개념을 알게되었으나 시간 내에 학습 후 적용하기는 어려울 것으로 판단해 적용하지 못함.