비동기 프로그래밍이 어렵지만 중요한 이유?
서버 응답 기다릴 때 다른 인터랙션에 반응하지 않는다면 화면이 멈춰있을 것.
👉 비동기 프로그래밍을 통해 서버 응답 기다리는 동안 다른 액션도 취해줘야 한다.
Javasctipt에서는 Callback, Promise, Observable 등을 통해 비동기 상황을 핸들링할 수 있음.
function fetchAccounts(callback){
fetchUserEntity((err,user) => {
callback(err, null);
return;
}
fetchUserAccounts(user.no, (err, accounts) => {
if(err !=null) {
callback(err, null);
return;
}
callback(null, accounts);
});
});
}
- 복잡함.
- 성공&실패의 경우가 섞여서 처리되고, 매번 비동기 호출시마다 에러처리를 해줘야 함.
async function fetchAccounts() {
const user = await fetchUserEntity();
const accounts = await fetchUserAccounts(user.no);
return accounts;
}
성공하는 경우만 다루고, 실패하는 경우는 catch 절에서 분리해 처리한다. '실패'하는 경우에 대한 처리를 외부에 위임할 수 있다.
좋은 비동기 코드?
성공/실패의 경우를 분리해 처리한다
👉 비즈니스 로직을 파악하기 쉽다.
const {data, error} = useAsyncValue(()=>{
return fetchSomething();
})
react-query, SWR같은 라이브러리 활용하여
Promise를 반환하는 함수를 React Hook의 인자로 넘기고,
Promise의 상태 변화에 따라 Hook이 반환하는 data, error의 값을 적절히 채워줌.
실제 컴포넌트를 만든다면,
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>
}
이런 식으로
➡️ 성공&실패하는 경우가 섞여서 처리된다.
➡️ 실패하는 경우에 대한 처리를 외부에 위임하기 어렵다.
↪️ 여러 개의 비동기 작업이 동시에 실행된다면 even worse 🙅♀️
async function fetchFooBar() {
const foo = await fetchFoo();
const bar = await fetchBar(foo);
}
위와 같이 간단하게 작성했을 것.
But, React에서 Hook or state를 사용하는 방식으로는 위와 같이 간단하게 비동기 처리가 어려움.
특히 2가지 이상 로직이 들어갈 때 더더욱 어려워짐.
<!아직은 실험 단계임!>
React Suspense for Data Fetching
컴포넌트는 성공한 상태만 다루고,
로딩&에러 상태는 외부에 위임함으로써 동기와 거의 같게 사용할 수 있는 기능
위와 같이 사용하는 라이브러리의 옵션으로 사용 가능.
토스팀에서는 일부 내부 프로덕트에서 적용중.
데이터가 준비되는대로 하나씩 자연스럽게 보여줄 수 있어서!! 좋은 사용자 경험!
이렇게 코드 조각을 감싸는 맥락으로 책임을 분리하는 방식 : 대수적 효과라고 함
+++ 사용자 경험 향상시킬 수 있는 기술 키워드