이 시리즈는 저만의 FE 컨벤션, 코드 스타일 등을 만들고자 Toss의 SLASH 영상과 기술 블로그 등을 참고하여 만들었습니다.
SLASH 21에서 박서진님께서 발표하신 "프론트엔드 웹 서비스에서 우아하게 비동기 처리하기" 영상을 분석하였습니다.
마지막에 더 공부하면 좋을 키워드까지 던져주시다니... 아주 알차네요🥹 감사합니다 서진님🙇🏻♂️ 프로젝트에 써먹을 부분들이 많은 것 같습니다. (해피~😊)
저는 깊게 생각하지 않고 로딩 & 에러 상태를 내부에서 처리하는 것을 너무 당연하게 받아들이고 있었는데, 확실히 좋은 코드를 보고 나니 제가 적었던 코드들이 지저분했다는 생각이 드네요. 비동기 처리할 때, Suspense 기능을 꼭 써보려고 합니다.
10여 년 전 jQuery와 같은 라이브러리를 쓰면서 명령형으로 프로그래밍을 하다가 React/Vue.js와 같이 선언적인 프로그래밍을 지원하는 프레임워크들이 나오면서 개발자들이 신경 써야 하는 부분들이 많이 줄게 되었다.
그럼에도 가장 어려운 부분을 꼽자면, "비동기 프로그래밍" 이다.
function Profile() {
const foo = useAsyncValue() => {
return fetchFoo();
}
if (foo.error) return <div>로딩 실패</div>
if (!foo.data) return <div>로딩 중</div>
return <div>{foo.data.name}님 안녕하세요!</div>
[Hooks]
: Hooks은 선언적인 API를 활용하여 컴포넌트를 감싸는 React 프레임워크가 실제 작업을 대신 수행해 준다.
+) Class 컴포넌트에서는 컴포넌트의 라이프 사이클에 맞춰 다양한 작업을 명령형으로 해준다.
[Suspense]
: 자식 컴포넌트가 완료될 때까지 fallback을 표시할 수 있는 기능이다. (비동기를 동기적으로 바꿔줌)
컴포넌트에서는 비동기적인 리소스를 선언하고, 그 값을 읽어온다고 '선언'하기만 했다. 그러면 실제 로딩 상태나 에러 상태 처리는 컴포넌트를 감싸는 부모 컴포넌트가 대신해 주었다.
: React 팀에서 로딩 & 에러 상태는 외부에 위임함으로써 동기적인 코드와 큰 차이가 없는 코드를 만들겠다는 목표로 "React Suspense for Data Fetching"을 만들었다.
function FooBar() {
const foo = useAsyncValue(() => fetchFoo());
const bar = useAsyncValue(() => fetchBar(foo));
return <div>{foo}{bar}</div>;
}
<ErrorBoundary fallback={<MyErrorPage />}>
<Suspense fallback={<Loader />}>
<FooBar />
</Suspense>
</ErrorBoundary>
export const templateSetSelector = selectorFamily({
key: '@messages/template-set',
get: (no: number) => async () => {
return fetchTemplateSet(no);
},
});
function TemplateSetDetails({ templateSetNo }: Props) {
const templateSet = useRecoilValue(templateSetSelector(templateSetNo));
/* 이 아래에서는 templateSet이 존재하는 것이 보장됨 */
}
<Suspense fallback={<Skeleton />}>
<TemplateSetDetails />
</Suspense>
+) Data fetching을 위해 React Query를 사용했었는데, Recoil의 selectorFamily를 활용해 봐야겠습니다.