✨ 시작하게된 배경
이번 프로젝트는 이전 프로젝트를 끝내고 react-query에 대해서 학습을 하고난 뒤 react-query를 사용하여 프로젝트를 진행하여 더 깊게 알고싶어 진행하게된 프로젝트다. 주제를 선정하게된 배경은 전년도 중반기쯔음 가벼운 마음으로 주식을 시작하였었는데
주식 차트를 계속 보고 구석구석 존재하는 기능들을 직접 사용해보고 실시간으로 계속 변동되는 데이터들을 보며 흥미를 느껴 나도 주식 사이트를 만들어보고 싶다고 생각이 들었었던적이 있어 그 때의 기억을 살려 주식이라는 주제로 프로젝트를 진행하게 되었다.
✨ 프로젝트를 진행하며 느낀 점 (힘들었던 것, 배운 것 등등)
지속적으로 변하는 데이터를 직접적으로는 접하지 못했던터라 해당 데이터들을 모든 컴포넌트에서 데이터가 일관성 있게끔 관리되도록 하고 지속적으로 변하는 데이터 때문에 여러 컴포넌트들이 연쇄적으로 많은 리렌더링을 일으키는 문제들과 아직 완전히 학습이 되지않은 react-query 라이브러리에 대해서 적응하고 적용을 하느라 정말 많이 힘들었다.
그래도 나를 힘들게했던 여럿 문제들에 대해 직면하고 헤쳐나감으로 인해서 확실히 배운것이나 깨달은 것은 많다고 자부할 수 있다.
겪었던 문제를 해결했던 상황으로는
1. 커뮤니티의 댓글 생성, 수정, 삭제에서 활용하였던 Optimistic Updates (낙관적 업데이트).
export const useCreateComment = () => {
const { stockName } = useParams<StockDetailParams>();
return useMutation<CommentData, AxiosError, CommentData>(
[QUERY_KEYS.CREATE_COMMENT],
(commentContent: CommentData) => createComment(commentContent),
{
onMutate: async (newComment: CommentData) => {
await queryClient.cancelQueries({
queryKey: [`${QUERY_KEYS.GET_COMMENT_LIST}/${stockName}`],
});
const previousComment: CommentData[] =
queryClient.getQueryData<CommentData[]>([
`${QUERY_KEYS.GET_COMMENT_LIST}/${stockName}`,
]) || [];
const updatedTodos: CommentData[] = [...previousComment, newComment];
queryClient.setQueryData<CommentData[]>(
[`${QUERY_KEYS.GET_COMMENT_LIST}/${stockName}`],
updatedTodos
);
return { previousComment };
},
onError: (err, newComment, context: any) => {
queryClient.setQueryData<CommentListData[]>(
[`${QUERY_KEYS.GET_COMMENT_LIST}/${stockName}`],
context?.previousTodos
);
},
onSettled: () => {
queryClient.invalidateQueries([
`${QUERY_KEYS.GET_COMMENT_LIST}/${stockName}`,
]);
},
}
);
};
낙관적 업데이트는 말 그대로 낙관적으로 업데이트 해버리는건데 구현했던 기능 중 댓글 생성 코드만을 예제로 들자면
현재 요청을 cancelQueries를 통해 쿼리를 취소하고 getQueryData로 업데이트 이전 데이터를 가져온 뒤 새로운 댓글을 getQueryData로 가져온 데이터에 추가하고 합쳐진 데이터를 setQueryData을 통해 쿼리를 업데이트 하는 방식으로 사용하여 사용자에게 뛰어난 경험을 줄 수 있게끔 하였다.
2. suspense 사용 시 겪었던 데이터 폭포수 현상
suspense를 제대로 알지못하고 사용했을 때 겪었던 데이터가 폭포(Waterfall)처럼 순차적으로 호출이 되어 로딩 화면이 장시간 노출되어버렸던 문제를 useSuspenseQuery를 사용하여 (트러블 슈팅 링크 첨부)을 통해 해결하였었고
3. 주식 매수/매도 후에도 데이터가 최신화 되지않던 현상
export const useStockTrading = async (
stockTradingRequestBody: TradingStockInfo
) => {
try {
const actionType = stockTradingRequestBody.actionType;
const stockName = stockTradingRequestBody.stock_name;
actionType === 'buy'
? await buyStock(stockTradingRequestBody as TradingStockInfo)
: await sellStock(stockTradingRequestBody as TradingStockInfo);
const stockChartAllQueryKeys = queryClient
.getQueryCache()
.findAll([`${QUERY_KEYS.STOCK_PRICE_HISTORY}/`]);
await queryClient.refetchQueries(stockChartAllQueryKeys);
await queryClient.refetchQueries([
`${QUERY_KEYS.STOCK_IN_POSSESSION}/${stockName}`,
]);
} catch (error) {
console.error('Stock trading failed:', error);
toast.error(`Stock trading failed: ${error}`);
}
};
주식 매수/매도 후에도 변하지않았던 문제가 있었는데 해당 문제는 주식 매수/매도를 성공적으로 끝마쳤다면
getQueryCache()와 findall을 통해 해당 쿼리키가 포함되는 데이터를 refetchQueries를 통해 데이터를 refetch해서
사용자의 좋은 경험을 증대시키는 좋은 성과를 이루었다.
물론 이번 프로젝트를 끝내는 현 시점에서도 react-query의 흐름이나 기본적인 부분에 대해서는 많이 이해가 되고 응용(?)하는 능력도 길러진 것 같으나 react-query에 대해서 아주 깊게까지는 사용해보지 못했던 것 같아 아쉽기는 하다.
다음 프로젝트를 진행하게 되면 조금 느리더라도 react-query에 대해서 더 깊게 공부하여 사용해보고 싶고 tdd에 대해서도 면밀히 살펴보고 적용해보고싶다.
✨ 프로젝트를 마무리하며 느낀점
이번 프로젝트를 끝내며 분명 뿌듯한 부분도 많겠지만 아쉬운 마음도 여럿 남아있다.
1. react-query를 깊게 써보지 못한것 같은 점.
2. 내가 좋은 코드를 짠게 맞나 ? 에 대한 의문이 남는 점.
3. 나의 프로젝트 디렉토리 구조가 좋은 구조가 맞나 ? 에 대한 의문이 남는 점.
4. 디자이너와 백엔드와 협업을 하지않고 혼자 진행하며 api의 데이터 구조나 전체적인 UI에 대한 디자인이 매우 아쉬운 점
등등... 사실 말하자면 끝도 없다.
매 번 항상 같은 마음이 드는 아쉬운 점은 내가 좋은 구조로 좋은 코드를 짜고 있는게 맞나? 라는 의문이 항상 맴도는 것이다.
이전 회사에서도 그렇고 이번 프로젝트에서도 그렇고 나는 항상 프론트엔드 코드에 대해서는 항상 혼자 짜고있다보니
답답할 수 밖에 없는 심정이다 ...
이건 내가 정말 많은 글들을 검토하며 최종으로 결정하고 사용하고있는 디렉토리 구조이다.
내부에 추가적으로 만들어진 폴더와 파일는 큰 기능들을 기준으로 폴더를 분류하였다
마지막으로 해당 프로젝트의 git hub의 주소를 남기며 이 회고록은 마무리 짓겠다.
https://github.com/Growing-Jiwoo/RealTime-Trading-Site
'프로젝트 회고록' 카테고리의 다른 글
[프로젝트 회고록] 사용자 위치 기반 부산 모범 음식점 추천 사이트 (0) | 2023.05.24 |
---|---|
[NUMBLE 회고록] 클론코딩의 정석_TypeScript + React 로 소개팅 앱 만들어보기 (2) | 2023.05.21 |