Suspense와 ErrorBoundary를 활용한 Concurrent UI 패턴

Sheryl Yun·2023년 12월 18일
0

React.js

목록 보기
16/24

예시 코드

  • API를 사용해서 서버의 데이터 값을 불러와 보여주는 경우
  • 예: 서버에서 할 일 목록(todos)을 받아와서 이를 보여주는 컴포넌트
    • 로딩 중일 때는 로딩 인디케이터를 보여주며 오류 발생 시에는 Error 폴백 컴포넌트를 보여줌
const Todos = () => {
	const [todos, setTodos] = useState();
    const [isLoading, setLoading] = useState(false);
    const [isError, setError] = useState(false);
    
    useEffect(() => {
    	setLoading(true);
        fetch('http://some.api.com/todo')
        	.then((res) => setTodos(res))
            .catch((error) => setError(true));
    }, []);
    
    if (error) {
    	return <p>Error !</p>
    }
    
    if (isLoading) {
    	return <p>Loading...</p>
    }
    
    return (
    	<ul>
        	{todos.map((todo) => (
                <li key={todo.id}>{todo.content}</li>
            )}
        </ul>
    );
}


const App = () => {
	return <Todos />
}

코드의 문제점

  • if문으로 이루어진 부분이 선언형이 아니라 명령형 코드
    • 다른 컴포넌트의 로딩중과 에러를 처리할 때도 동일한 로직을 계속 넣어줘야 함
    • 위 로딩중과 에러 로직 외에 다른 비즈니스 로직이 추가될 때 프로젝트 규모가 커질수록 결과물이 비대해지고 길어진 코드로 내용을 한눈에 알아보기 어려워짐

선언형으로 개선하기

  • 리액트 18 버전 기준으로 Suspense(로딩중)와 ErrorBoundary(에러)를 사용한 제어의 역전(IoC)을 통해 개선

제어의 역전
특정 로직(로딩 또는 에러 상태)에 따른 렌더링 제어권을 부모 컴포넌트에게 전가하고 현재 컴포넌트는 보여주고 싶은 화면에만 집중하는 방식

const Todos = () => {
	const [todos, setTodos] = useState();
    
    useEffect(() => {
    	fetch('http://some.api.com/todos')
        .then((res) => setTodos(res));
    }, []);
    
    return <ul>
    			{todos.map((todo) => (
                	<li key={todo.id}>{todo.content}</li>
                )}
    		</ul>;
}


const App = () => {
	return <ErrorBoundary fallback={<p>Error !</p>}>
    		<Suspense fallback={<p>Loading...</p>}>
            	<Todos />
            </Suspense>
    	</ErrorBoundary>
}

바뀐 점

  • Todos의 return문이 loading, error 등으로 나누어지지 않고 하나로 통일됨
    • ErrorBoundary와 Suspense를 통해 Todos가 가지고 있던 조건부 렌더링 부분의 제어권을 부모 컴포넌트인 App에 넘겨서 처리
      => 컴포넌트가 본인의 역할에 따른 관심사만 집중할 수 있기 때문에 이해하기 쉬운 선언형 컴포넌트를 만들 수 있음

참고 자료

선언형 프로그래밍으로 이해하기 쉬운 코드 작성하기

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글