예전에 토스에서 진행했던 SLASH 21이라는 컨퍼런스에서 소개된 영상을 가볍게 정리한 게시글입니다. 프론트엔드에서 비동기 처리를 하는 방법을 설명해주셨는데요. React의 Suspense와 recoil의 selector에 대해서 다뤘습니다. 지금 진행 중인 개인 프로젝트에서 적용해 볼 예정입니다. 설명하시는 분이 설명을 잘하셔서 저같은 초보자도 쉽게 이해할 수 있습니다. 간단하게 정리한 게시글이기 때문에 되도록이면 영상을 보는 것을 추천드립니다. 영상 링크는 하단에 있습니다.
funtion getBazFromX(x){
if (x === undefined) {
return undefined;
}
if (x.foo === undefined) {
return undefined;
}
if (x.foo.bar === undefined) {
return undefined;
}
return x.foo.bar.baz;
}
function getBazFromX(){
return x?.foo?.bar?.baz;
}
function fetchAccounts(callback){
fetchUserEntity((err, user) => {
if (err != null) {
callback(err,null);
return;
}
fetchUserAccounts(user.no, (err, accounts) => {
if (err != null) {
callback(err, null);
return;
}
callback(null, accounts);
})
})
}
async function fetchAccounts(callback){
const user = await fetchUserEntity();
const accounts = await fetchUserAccounts(user.no)
return accounts;
}
const { data, error } = useAsyncValue(() => {
return fetchSomething();
})
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>
}
function Profile(){
const foo = useAsyncValue(() => {
returb fetchFoo();
})
const bar = useAsyncValue(() => {
if (foo.error || !foo.data){
return undefined;
}
returb fetchBar(foo.data);
});
if (foo.error || bar.error) return <div>로딩에 실패했습니다.</div>
if (foo.error || bar.error) return <div>로딩 중입니다...</div>
return /* foo와 bar로 적합한 처리하기 */
}
Suspense가 목표로하는 코드
비동기로 데이터를 패칭하는 컴포넌트
function FooBar() {
const foo = useAsyncValue(() => fetchFoo());
const bar = useAsyncValue(() => fetchBar());
return <div>{foo}{bar}</div>
}
에러 상태와 로딩 상태는 어떻게 분리되는가?
<ErrorBoundary fallback={<MyErrorPage />}>
<Suspense fallback={<Loader />}>
<FooBar />
</Suspense>
</ErrorBoundary>
일반적인 Suspense / ErrorBoundary의 용법
어떻게 사용할 수 있는가?
export const templateSetSelector = selectorFamily({
key: '@messages/template-set',
get: (no: number) => async () => {
return fetchTemplateSet(no)
}
})
export const historiesOfTemplateSetSelector = selectorFamily({
key: '@pages/messenger/template-set/histories',
get: (templateSetNo: number) => async ({ get }) => {
return fetchHistoriesOfTemplateSet(templateSetNo)
}
})
funtion TemplateSetDetails({ templateSetNo }: Props){
const templateSet = useRecoilValue(templateSetSelector(templateSetNo))
}
/* 이 아래에서는 templateSet이 존재하는 것이 보장됨 */
<Suspense fallback={<Skeleton />}>
<TemplateSetDetails />
</Suspense>