-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
경북대 FE_이은경 3주차 과제 #110
base: main
Are you sure you want to change the base?
경북대 FE_이은경 3주차 과제 #110
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다~ 리뷰 남깁니다!
const observerRef = useRef<IntersectionObserver | null>(null); | ||
const loadMoreRef = useRef<HTMLDivElement>(null); | ||
|
||
useEffect(() => { | ||
const loadGoodsData = async () => { | ||
setIsLoading(true); | ||
setErrorMessage(null); | ||
if (isFetchingNextPage) return; | ||
|
||
if (observerRef.current) observerRef.current.disconnect(); | ||
|
||
try { | ||
const productsResponse = await fetchThemeProducts(themeKey); | ||
if (productsResponse.products.length === 0) { | ||
setErrorMessage('상품이 없어요.'); | ||
} else { | ||
setGoodsList(productsResponse.products); | ||
} | ||
setIsLoading(false); | ||
} catch (error) { | ||
if (axios.isAxiosError(error)) { | ||
if (error.response) { | ||
switch (error.response.status) { | ||
case 404: | ||
setErrorMessage('상품을 찾을 수 없습니다.'); | ||
break; | ||
case 500: | ||
setErrorMessage('서버 오류가 발생했습니다.'); | ||
break; | ||
default: | ||
setErrorMessage('예기치 않은 오류가 발생했습니다.'); | ||
} | ||
} else if (error.request) { | ||
setErrorMessage('요청이 있지만 응답을 받지 못했습니다.'); | ||
} else { | ||
setErrorMessage('요청 설정 중 오류가 발생했습니다.'); | ||
} | ||
} else { | ||
setErrorMessage('에러가 발생했습니다.'); | ||
} | ||
setIsLoading(false); | ||
observerRef.current = new IntersectionObserver((entries) => { | ||
if (entries[0].isIntersecting && hasNextPage) { | ||
fetchNextPage(); | ||
} | ||
}; | ||
}); | ||
|
||
loadGoodsData(); | ||
}, [themeKey]); | ||
if (loadMoreRef.current) observerRef.current.observe(loadMoreRef.current); | ||
|
||
if (isLoading) { | ||
return <Message>Loading...</Message>; | ||
} | ||
return () => { | ||
if (observerRef.current) observerRef.current.disconnect(); | ||
}; | ||
}, [isFetchingNextPage, fetchNextPage, hasNextPage]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
intersection observer를 사용하는 부분을 추상화하면 어떨까요?
굳이 옵저버를 사용하기 위한 코드를 컴포넌트에 흩뿌려 낮은 응집도를 만들 필요는 없다고 생각해요.
useIntersectionObserver과 같은 훅을 만들어서 선언적으로 사용해보시면 좋을 것 같아요
@@ -49,6 +49,8 @@ module.exports = { | |||
}, | |||
], | |||
'@typescript-eslint/no-use-before-define': ['off'], | |||
'react-hooks/exhaustive-deps': 'off', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 규칙은 절대 끄지 말아주세요~
useEffect를 사용할때 해당 룰로 인해 에러가 검출된다면 그 useEffect는 잘못 사용중인 것이에요.
어떤 effect에서 문제가 발생했던건가요?
@@ -49,6 +49,8 @@ module.exports = { | |||
}, | |||
], | |||
'@typescript-eslint/no-use-before-define': ['off'], | |||
'react-hooks/exhaustive-deps': 'off', | |||
'@typescript-eslint/no-shadow': 'off', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 룰을 off한 이유는 무엇인가요?
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-intersection-observer": "^9.13.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사용하지 않는 의존성은 제거해주세요~
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-intersection-observer": "^9.13.0", | ||
"react-query": "^3.39.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
왜 3버전을 사용하신걸까요?
현재는 5버전이 최신입니다. 이름도 tanstack query로 변경되었어요! 확인해보시고 최신 버전으로 개발하시는 것을 추천드립니다.
3주차 과제 step3와 4까지 전체 제출입니다!
3주차 질문
1. CORS 에러는 무엇이고 언제 발생하는지 설명해주세요. 이를 해결할 수 있는 방법에 대해서도 설명해주세요.
CORS(Cross Origin Resource Sharing)는 교차-출처 리소스 공유로 말할 수 있는데 서로 다른 도메인간에 자원을 공유하는 것을 의미하는데 기본적으로 브라우저는 차단되어있다.
URL 구조에는 출처인 protocal, host, 포트번호가 있는데 이 출처를 비교하는 로직이 서버에서 구현되는 것이 아니라 브라우저단에서 이루어져서 cors 정책을 위반하는 리소스를 요청해도 일단 정상적으로 응답하고 브라우저가 이 응답을 분석해서 CORS 위반이라고 생각하면 응답을 버리게되면서 발생!
클라이언트에서 해결
가장 간단한 방법은 Proxy 패턴을 이용해서 클라이언트 웹 페이지에서 직접 하는 것이 아니라 페이지에서 클라이언트 서버로 보내고 여기서 다시 백엔드 서버로 요청을 보내도록 한다. 서버끼리 통신할때는 CORS 정책이 적용되지 않기 때문!
서버에서 해결
2. 비동기 처리 방법인 callback, promise, async await에 대해 각각 장단점과 함께 설명해주세요.
Callback
다른 함수가 실행을 끝낸 뒤 실행(call back)되는 함수(나중에 호출되는 함수)를 말한다.
장점 : 자바스크립트는 싱글스레드를 사용하는데 멈춤을 방지해준다.
단점 : 에러/예외처리 어려움, 중첩으로 인한 복잡도 증가
Promise
싱글스레드인 자바스크립트에서 비동기 처리를 위해 사용한 callback 함수의 단점을 해결하기 위해 프로미스 객체를 언어적 차원으로 지원
장점 : 콜백함수에 비해 가독성이 좋고 비동기 처리를 동기적으로 보이게하며 순서파악에 용이
단점 : 콜백지옥과 같은 맥락으로 then을 연쇄적으로 호출하면 코드가 복잡해지고 가독성이 떨어진다.
기존의 비동기 처리방식인 콜백함수의 단점을 보완하기위한 프로미스의 단점을 해결하기위한 최신 문법
장점 : 동기코드처럼 보이게 작성해 가독성을 높일 수 있고 사용 방법이 굉장히 간단하다.
3. react query의 주요 특징에 대해 설명하고, queryKey는 어떤 역할을 하는지 설명해주세요.
React Query는 데이터 Fetching, 동기화, 서버 데이터 업데이트 등을쉽게 도와주는 라이브러리
특징은 동일한 데이터에 대한 중복 요청 제거, 오래된 데이터 상태파악 후 updating을 지원, 리액트 훅과 유사한 인터페이스 제공 등이 있다.
queryKey는 useQuery마다 부여되는 고유한 키 값
문자열로 사용되기도하고 배열의 형태로 사용될 수도 있으며 이것을 통해 다른 곳에서도 해당 쿼리의 결과를 꺼내올 수 있다.