치춘짱베리굿나이스
[프리온보딩] 220524 그룹과제 #3 본문
그룹과제 #3
공식적인 내생각
내 파트에서 할 수 있는 건 다 해서 추가 기능을 구현했다
광고 만들기 버튼을 누르면 진짜로 광고를 만들 수 있게 만들고 싶었는데 어찌저찌 작성하다보니…. 기본내용 구현보다 광고추가 기능 하나가 더 빡셌던 것 같다
중간중간 컴포넌트 분리나 합치기 등 리팩토링도 해가면서 했더니 밤을 꼴닥 새버렸다
하하
작업 내용
숫자 3자리마다 쉼표 찍어주기 - toLocaleString()
const number = 1234;
number.toLocaleString(); // 1,234
이렇게 쉬울수가
정규식은 다시 잊어버리도록 해야겠다
프로그래머 최악의 적 정규식
인자를 추가함으로써 숫자를 아라비아어, 한자 등 특정 언어로 바꾸거나 스타일을 추가할 수 있다 (달러, 엔화, 한화 등…)
promise랑 친구먹음
export const getAdListData = () => {
const promise = new Promise((resolve: (value: IAdData) => void, reject) => {
const data: IAdData = store.get('adsData')
if (!data) reject();
else resolve(data);
})
return promise
.then(setFetchDelayPromise(500))
.then((data: IAdData) => data)
.catch(() =>
axios
.get('/wanted_FE_ad-list-data-set.json')
.then(setFetchDelay(500))
.then((response: AxiosResponse) => response.data)
);
};
원래는 axios로 데이터 받고 바로 필터링까지 진행했는데, 데이터를 추가하려 하니 필터링을 거치지 않은 원본 데이터가 필요해서 + 로컬 스토리지에 데이터 넣었다 빼는 부분이 필요해서 fetch 함수 (getAdListData)를 개조했다
그와중에 store.get을 먼저 진행하고, 로컬 스토리지에 데이터가 존재하지 않을 경우에만 axios로 데이터를 받아와야 하기 때문에 promise + then / catch를 이용했다
로컬 스토리지에 데이터가 없었을 경우 reject를, 존재했을 경우 resolve를 통해 데이터 fetching 성공 여부를 결정하고, 실패했을 경우 (reject) catch 문을 통해 axios로 데이터를 받을 수 있도록 하였다
이중 Promise문이 되긴 했는데 어차피 useQuery 훅에서 사용하려면 Promise 형태여야 해서 (+ 지정한 동작이 끝날 때까지 기다리고 성공, 실패 여부에 따라 쉽게 추가 동작을 구현할 수 있어서) Promise를 사용했고 결과는 매우 괜찮았다
로컬 스토리지에 데이터가 없을 경우 예외처리를 복잡하게 하지 않고 바로 axios로 넘어갈 수 있기도 하고, 과제에서 요구한 delay도 쉽게 넣을 수 있어서 매우 쓸만하다
const filter = new Promise<IAdData>((resolve) => {
if (adsFilterIndex === 0) resolve(data);
const newData: IAdData = {
count: 0,
ads: [],
}
newData.ads = data.ads.filter((ad: IAd) => ad.status === STATUS[adsFilterIndex]);
newData.count = newData.ads.length;
resolve(newData);
});
filter.then((newData) => setFilteredData(newData));
커스텀 훅 내에서 필터링을 수행할 때도 Promise를 사용했다
이번에는 필터링이 끝난 데이터를 filteredData 상태에 넣어야 했기 때문
setState가 비동기로 동작하기 때문에 동작 관리를 해주지 않으면 그냥 빈 데이터가 홀랑 들어가버린다
그걸 막기 위해 then을 사용해서 후속동작으로만 필터링 데이터를 설정할 수 있게 해 주었고, 어차피 예외처리할 요인은 없으니 resolve만 사용하였다
Promise가 쓸 때마다 조금씩 헷갈려서 매번 문서 찾아가면서 하긴 하는데 그래도 많이 익숙해진듯하다
Promise 내에서 then으로 고의 딜레이 주기
export const setFetchDelay = (ms: number) => {
return (x: AxiosResponse) => {
return new Promise<AxiosResponse>((resolve) => {
setTimeout(() => resolve(x), ms);
});
};
};
export const setFetchDelayPromise = (ms: number) => {
return (x: IAdData) => {
return new Promise<IAdData>((resolve) => {
setTimeout(() => resolve(x), ms);
});
};
};
과제 요구사항 중 로딩 화면을 구현하고 이를 위해 임의로 딜레이를 주어야 하는 부분이 있었다
결과값이 AxiosResponse일 때 (데이터 받아올 때 axios 쓴 경우) 와 IAdData일 때 (로컬 스토리지에서 가져왔을 때) 를 다르게 구현했다
유니온타입을 사용해서 AxiosResponse일수도 IAdData일 수도 있습니다 라고 합쳐서 작성하면 해당 타입의 인수로 할당할 수 없다면서 오류가 나더라
axios.get().then(setFetchDelay(500)).then((res) => res.data);
// setFetchDelay가 반환하는 함수를 합친 모습
axios.get().then((x: AxiosResponse) => {
return new Promise<AxiosResponse>((resolve) => {
setTimeout(() => resolve(x), 500);
});
}).then((res) => res.data);
사용 방법은 위와 같다
setFetchDelay에 인자로 500을 넣으면, 반환값은 아래와 같이 Promise를 사용하는 함수가 된다
Promise에 의해 setTimeout으로 500ms를 쉬어주고, 다 쉬고 나면 인자로 받은 x를 resolve 함수를 통해 그대로 반환해주는 형식
따라서 axios.get 에서 받은 인자를 그대로 (res) ⇒ res.data 까지 가져와서 사용할 수 있다
비동기 처리가 이렇게 간단하다
조건부 렌더링 (&& 연산자 등) / display: none
- 조건부 렌더링: 조건의 true / false 여부가 바뀔 때마다 리렌더링되므로, 상태값도 초기화된다
- 따라서 form 등 내용물의 초기화가 필요할 때 사용하면 좋다
display: none: 렌더링은 계속 되어있는 상태에서 스타일로 숨김 / 공개 처리만 하는 것이기 때문에 내용물 및 상태값도 그대로 남아있다- 내용물의 초기화가 필요 없거나, 값을 유지하고 싶을 때 사용하면 좋다
아무 생각 없이 display: none을 썼더니 form 안의 내용물이 계속 남아있어서…. 아예 리렌더링을 반복하는 방식을 사용했다
useEffect에 dependency로 isOpen 상태값을 걸어줄까 했는데 form 안에서 사용하는 상태값이 너무 많아서 일일히 초기화하는 것도 일이다
일일히 일이다
'프로젝트 > 원티드 프리온보딩' 카테고리의 다른 글
| [프리온보딩] 220526 그룹과제 #3 종료 + 그룹과제 #4 (0) | 2022.05.27 |
|---|---|
| [프리온보딩] 220525 그룹과제 #3 (0) | 2022.05.26 |
| [프리온보딩] 220523 그룹과제 #3 (0) | 2022.05.24 |
| [프리온보딩] 220517 강의 메모 02 (코드 예시) (0) | 2022.05.23 |
| [프리온보딩] 220521 그룹과제 #2 종료 + 그룹과제 #3 (0) | 2022.05.23 |