728x90
SMALL
명령형 프로그래밍
모든 동작을 순차적으로 지시해야하기 때문에 구현 과정에서 부수적인 코드가 점점 쌓이게 된다.
async function fetchTodo() {
try {
const res = await fetch("endpoint3");
if (!res.ok)
throw new Error("투두를 받아오다 에러가 발생했어요. 하지만 무슨 에러일까요?")
const data = res.json();
setTodo(data);
} catch(error) {
console.error(error);
setErrorState(error);
}
}
fetch를 통한 데이터 요청 => 상태 업데이터 => 에러처리
절차적인 프름이 명확하게 명시된다.
따라서 추가적인 상태 업데이트나 요청 과정에서 필요한 기능이 추가되면 어디에 상태를 추가해야 하는지 혹은 어떤 로직을 수정해야 하는지 고려해야 하니 유지보수가 점점 어려워진다.
1. 중복 코드의 증가 - 비슷한 api 요청이 추가될 때마다 똑같은 try-catch 문을 반복해야 한다.
2. 유지보수가 힘들어진다. - 데이터 요청 + 상태 업데이트 + 에러 처리 흐름이 여러 곳에 반복되어 있는 상태에서 서버와 합의된 api 구조 혹은 상태 업데이트 로직이 변경되면 모든 api 호출 함수를 수정해야 한다.4
3. 에러 처리의 일관성 부족 - api 호출마다 setError를 따로 관리하면 에러 메세지가 일관되지 않을 수 있다.
선언형 프로그래밍
결과를 기술하는 방식으로 무엇을 할지 선언만하고 어떻게 할 것인지는 라이브러리 혹은 프레임워크에 맡기는 방식
ui가 복잡해질수록 유지보수는 어려워진다. 특히 비동기 데이터 요청, 에러 핸들링, 상태 관리 등 명령형 방식은 코드가 점점 복잡해지고 버그를 유발할 가능성이 커지게 된다.
실제로 리액트의 철학은 상태에 맞게 ui를 선언적으로 표현하는 것.
import { ReactNode, Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useQueryErrorResetBoundary } from '@tanstack/react-query';
interface AsyncBoundaryProps {
children: ReactNode;
pendingFallback?: ReactNode;
rejectedFallback?: ReactNode;
onReset?: () => void;
resetKeys?: unknown[];
}
export function AsyncBoundary({
children,
pendingFallback,
rejectedFallback,
...errorBoundaryProps
}: AsyncBoundaryProps) {
return (
<ErrorBoundary
fallback={(rejectedFallback as React.ReactElement) ?? null}
{...errorBoundaryProps}
>
<Suspense fallback={pendingFallback}>{children}</Suspense>
</ErrorBoundary>
);
}
'코딩 정보 > React' 카테고리의 다른 글
| 스크롤 락에 대해 알아보자 (1) | 2026.06.15 |
|---|---|
| [React] 리액트 피버와 함께 랜더링 이해하기 (8) | 2025.08.12 |
| [React] useOptimistic을 통해 낙관적 업데이트를 구현해보자 (7) | 2025.08.04 |
| [React] useLayoutEffect 와 useEffect (2) | 2025.08.02 |
| [React] stompjs, sockjs를 통해 소켓 통신 하기 (0) | 2025.04.19 |