우리가 흔히 데이터를 받아와 필터링을 해야하는 로직을 짜아할 때가 있다. 이때 필터링을 구현하기 위해서는 다음과 같은 두가지 접근이 있을 수 있다!
처음 단 한번, 외부 API로부터 명언 목록을 받아오고, filter 함수를 이용한다.
검색어가 바뀔 때마다, 외부 API를 호출한다.
이 둘의 각각 장단점은 무엇일까? 앞서 예저에서는 storageUtil.js
에서 LocalStorage API를 직접 구현하였지만 이는 외부 API처럼 구현했다고 말할 수 있습니다. 즉, 서버 요청으로 대체할 수 있습니다. 만일 서버에서 수십만개의 명언을 제공한다고 가정해본다면 클라이언트가 필터링 구현을 생각하지 않아도 되지만, 번번한 HTTP 요청이 일어나게 될 것이며, 서버에 부담이 되어진다. 하지만 컴포넌트 내부에서 처리하게 된다면, HTTP 요청의 빈도를 줄일 수 있다는 장점이 있지만, 브라우저(클라이언트)의 메모리에 많은 부담이 늘어나게 된다.
장점 | 단점 | |
---|---|---|
컴포넌트 내부에서 처리 | HTTP 요청의 빈도를 줄일 수 있다 | 브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게 되므로, 클라이언트의 부담이 늘어난다 |
컴포넌트 외부에서 처리 | 클라이언트가 필터링 구현을 생각하지 않아도 된다 | 빈번한 HTTP 요청이 일어나게 되며, 서버가 필터링을 처리하므로 서버가 부담을 가져간다 |
임의로 구현한 storageUtil.js
대신에 fetch API를 써서, 서버에 요청한다면 코드는 어떻게 될까? 명언을 제공하는 API의 엔드포인트가 http://서버주소/proverbs
라고 가정해보자
useEffect(() => {
fetch(`http://서버주소/proverbs?q=${filter}`)
.then(resp => resp.json())
.then(result => {
setProverbs(result);
});
}, [filter]);
모든 네트워크 요청이 항상 즉각적인 응답을 가져다주는 것은 아니다. 외부 API 접속이 느릴경우를 고려하여, 로딩 화면(loading indicator)의 구현은 필수적이다.
[그림] loading indicator
[그림] loading placeholder
우리가 보다 나은 UX를 구현하기 위해서는 위의 그림처럼 표시해주는 것이 좋다. 이때에는 상태처리를 이용해서 작성하면 된다!
const [isLoading, setIsLoading] = useState(true);
// 생략, LoadingIndicator 컴포넌트는 별도로 구현했음을 가정합니다
return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}
fetch 요청의 전후로 setLoading
을 설정해주어서 보다 나은 UX를 구현할 수 있다!
useEffect(() => {
setIsLoading(true);
fetch(`http://서버주소/proverbs?q=${filter}`)
.then(resp => resp.json())
.then(result => {
setProverbs(result);
setIsLoading(false);
});
}, [filter]);