1️⃣6️⃣주차 24.01.01 ~ 24.01.07
프로젝트 2주차이자 sprint2기간이었다.
일단, sprint1은 공통 컴포넌트가 주 목표였다.
프로젝트 전반에 걸쳐 사용될 공통 컴포넌트를 선정하고, 팀원들끼리 분담하여 개발하였다. 스토리북을 사용하여 테스트와 디자인을 맞춰볼 수 있었다.
위의 적은 것 처럼 지난 스프린트에서 만든 공통 컴포넌트들 중 보완할 점을 찾아 수정했다.
이 중 나는 Button과 Card를 맡았었는데, 특히 Card의 경우, Icon과 Tag 등 다른 팀원이 만든 컴포넌트를 내부에 추가해야했다. 그러면서 여러 요구사항이 더 생겼고 회의해가며 수정하는 과정을 거쳤다.
회고 ☃︎
props를 확장할 수 있게 만들었어야했다! 특히 스타일 관련된 props들은 생각보다 다양한 변경이 필요했고 이를 하나 값으로 받는거보다 inline-style 객체를 받을 수 있도록 하는게 나은 것 같다.
응답 데이터 타입에 대해 인터페이스로 정의해두었다.
그리고 커스텀화 할 수 있는 모델인 IPost 중 title 값 타입에 대해 어떻게 커스텀하여 받을지 상의했다.
만드려고 하는 기능과 거기에 필요한 데이터 구조를 백엔드에 요청해서 새로운 api를 받는게 아닌 정해진 api 구조에서 커스텀 한다는 것이 어색하기도 했고 비효율적이다라고도 느꼈지만, 주어진 것을 활용해쓰는 방법을 경험해본 것 같다.
//Post 모델 중 title 필드 커스텀값
export interface IPostTitleCustom {
postTitle: string; // 타이틀1
contents: string; // '본문'
status: 'Opened' | 'Scheduled' | 'Closed'; // 모집 중 | 모임 예정 | 모임 종료
tags: string[]; // ['tag1','tag2','tag3','tag4']
mentions: IMentionedUser[]; // [{id: '23', fullName: 'MinSuKim'}]
meetDate: [Date, Date]; // 변경 // 투표 시작,끝 날짜 ['2022-12-23 11:20:20TZ','2022-12-23 11:20:20TZ'])
peopleLimit: number;
vote: IVote[]; // [{id: 'dfnkdflad', votedDate: ['2022-12-23 11:20:20TZ','2022-12-23 11:20:20TZ']}] <== 날짜 아니라 타임테이블 배열 인덱스
cardId: string; // 포스트 _id
author: string; // Post author는 User 지만, 컴포넌트에 전달할땐 User.fullName을 줘야함!
isLiked: boolean; // 포스트 좋아요는 포스트 likes 중에서 user로 필터링해서 찾아야합니다
}
만들어둔 컴포넌트들을 활용해서 페이지 단위 개발을 시작했다. 크게 MainPage, DetailPage-본문, DetailPage-타임테이블, MyPage로 나누어 분담했다. 각자 만든 컴포넌트가 주로 쓰일 페이지를 담당하게 되어서, 나는 메인페이지를 맡았다. 구현한 것들은 다음과 같다.
api 연결에 앞서 customAxiosInstance와 요청 함수를 만들었다.
JWT토큰을 실은 요청과 그렇지 않은 요청을 구분하여 만들었다.
export const customAxios = (): AxiosInstance => {
const axiosInstance = axios.create({
baseURL: VITE_API_BASE_URL,
});
return axiosInstance;
};
export const customAxiosJWT = (): AxiosInstance => {
const jwt = getItem('JWT', '') as string;
const axiosInstance = axios.create({
baseURL: VITE_API_BASE_URL,
headers: { Authorization: `Bearer ${jwt}` },
});
return axiosInstance;
};
요청 METHODS에 대해서도 함수를 만들어두었다.
export const getApi = async <T>(url: string) => {
const res: AxiosResponse<T> = await customAxios().get(url);
return res;
};
export const getApiJWT = async <T>(url: string) => {
const res: AxiosResponse<T> = await customAxiosJWT().get(url);
return res;
};
AxiosResponse<T>
타입으로 준 이유는?
// index.d.ts
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
const response = await getApi<IUser[]>('/users/get-users');
이렇게 제네릭타입에 타입값을 주면 다음과 같이 타입을 인식한다.
const response: AxiosResponse<IUser[], any>
하지만,
이렇게 타입값을 주지 않으면
const response = await getApi('/users/get-users');
const response: AxiosResponse<unknown, any>
이렇게 응답 중 data에 대한 타입이 unknown으로 전달된다.
응답값을 변수에 받아 추가로 속성에 접근하는 등을 위해서 타입을 주어야 한다!
야근 코어타임
우리팀 특징이자 장점이자 규칙인 야근 코어타임! 이제 어느정도 익숙해졌고, 힘들지만 다들 착실히 들어오고 열심히 해줘서 좋다!
진행상황 공유
코어타임 전후, 야근코어타임 전후로 계속해서 진행상황을 물어본다. 어떤걸 작업했냐, 어디까지 했냐, 문제 없었냐, 이제 뭐할거냐 등등등... 팀장이란 역할을 맡아서 물어보게 되는 것도 있지만, 아무튼 팀 협업이니까 각자의 진행상황 공유와 조율이 너무나 중요하다는 걸 느끼고 있다. 가끔씩 비슷한 작업을 이중으로 하면서 생기는 비효율을 없애야한다고 생각했다.
원활히 진행되고 있는 것 같으면서도, 속도를 더 내야할 것 같기도 하고, 여러가지 불안도 많이 들고있다.. 팀원간의 속도가 다르다는 걸 많이 느끼고 있다. 당연히 담당한 양도 다르고 예상 못한 이슈를 만나서 그럴 수도 있는데, 한데 모아서 정리하고 다음 단계로 넘어가기 위해서 딜레이가 생기는 것이 조금 답답했다. 업무 분담과 일정 계획을 잘 해두지 못한 걸까 라는 아쉬움이 들었다.