[ 요약 ]
비즈니스 로직 한눈에 파악 가능
성공과 실패 코드 분리
성공하는 경우만 다루고 실패하는 경우는 외부에 위임
리액트는 ErrorBoundary 와 Suspense 로 로딩상태와 에러상태 분리 및 처리
토스 SLASH 21 프론트엔드 웹 서비스에서 우아하게 비동기 처리하기
그냥 봐도 읽기가 어렵다.
x.foo.bar.baz 에 안전하게 접근하기 위한 목적에 비해 코드가 복잡하다.
function 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;
}
optional chaining
으로 문제를 해결할 수 있다.
function getBazFromX(x) {
return x?.foo?.bar?.baz;
}
읽기 쉬운 이유
- 함수가 하는 일을 흐리는 if문 사라짐.
- 함수의 역할 한눈에 파악 가능.
성공하는 경우와 실패하는 경우가 섞여서 처리 -> 함수의 역할이 가려짐
비동기 처리할 때마다 에러체크 필요
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;
}
...
});
});
}
async/await
으로 해결.
function fetchAccounts(callback) {
const user = await fetchUserEntity();
const accounts = await fetchUserAcconts(user.no);
return accounts;
}
읽기 쉬운 이유
- 성공하는 경우만 다루고 실패하는 경우는 분리하여 처리
- 실패하는 경우는 외부에 위임
컴포넌트에서 로딩과 에러 처리를 동시에 수행한다.
funciton Profile() {
const foo = useAsyncValue(() => { return fetchFoo(); });
if (foo.error) return <div>로딩 실패</div>
if (!foo.data) return <div>로딩 중</div>
return <div>{foo.data.name}님 안녕하세요</div>
}
-> 성공하는 경우와 실패하는 경우가 섞여 있다.
-> 실패하는 경우에 대한 처리를 외부에 위임하기 어렵다.
- 성공한 경우에만 집중
- 로딩 상태와 에러 상태 분리
- 동기 코드와 유사하게 만듦
// Foobar.jsx
function Foobar() {
const foo = useMemo(() => fetchFoo());
const bar = useMemo(() => fetchBar(foo), [foo]);
return <div>{foo}{bar}</div>;
}
// index.js
<ErrorBoundary fallback={<ErrorPage />}> // 에러상태
<Suspense fallback={<Loader />}> // 로딩상태
<Foobar />
</Suspense>
</ErrorBoundary>
컴포넌트를 쓰는 쪽에서 로딩 처리와 에러 처리를 한다.
가장 가까운 Suspense의 fallback
으로 로딩 상태가 그려진다.
가장 가까운 ErrorBoundary가 componentDidCatch()
로 에러 상태를 처리한다.
모든 컴포넌트를 감싸는 것이 아니라 적당한 레벨 단위로 묶어준다.
react 18 에서 제공하는 기능
react에서 컴포넌트의 렌더 트리를 부분적으로 완성할 수 있다 -> UX 향상