티스토리 뷰
React의 예측 가능한(predictable) UI를 위한 설계 철학
리액트는 '어떤 상태가 주어지면, 항상 그에 대응하는 동일한 UI를 만들어야 한다'는 원칙을 따르고 있다.
이것이 바로 예측 가능(predictable)한 UI를 말한다.
// 상태가 같으면
const isLoggedIn = true;
// 언제나 같은 UI를 출력해야 함
return isLoggedIn ? <Dashboard /> : <Login />;
예측 가능한 UI는 왜 중요할까?
입력값(state)을 고정하면 결과(UI)를 예측할 수 있어 테스트가 쉬우며, 상태만 보면 어떤 UI가 나올 지 알 수 있기 때문에 디버깅이 쉽다.
컴포넌트는 side effect 없이 상태에 따라 렌더링되어 유지보수가 쉬우며, 선언형 프로그래밍이므로 명령형보다 DOM 조작이 직관적이다.
예시
비예측적
Component가 동적으로 undefined가 될 수 있으므로 버그, 에러, 렌더 실패 가능성이 있다.
let Component;
if (someCondition) {
import('./A').then((mod) => {
Component = mod.default;
});
}
return <Component />; // ❗ undefined일 수도 있음 → unpredictable
예측적
type만 보면 어떤 컴포넌트가 렌더링될지 명확하다.
const cardMap = {
image: ImageCard,
video: VideoCard,
};
const Component = cardMap[type];
return Component ? <Component {...props} /> : null;
리액트는 상태에서 UI로 이어지는 흐름을 예측 가능하게 유지해야한다.
이걸 위해 JSX 안에서 undefined와 같은 '불확실한 컴포넌트'는 피해야하며 조건부 렌더링, 명시적 매핑 구조를 잘 활용해서 개발해야한다.
예측 가능한(predictable) UI는 리액트가 '이벤트 → 상태 업데이트 → 렌더링'이라는 사이클을 항상 동일한 규칙으로 돌게 하는 것이 핵심이다.
명령형(imperative)와 선언형(declarative)
구분 | 설명 | 예시 |
명령형(Imperative) | "어떻게 동작할지"를 직접 지시하는 방식 | DOM을 직접 조작 |
선언형(Declarative) | "무엇을 보여줄지"만 선언, 상태에 따라 알아서 렌더 | React 방식 |
예시: 리스트 렌더링
선언형
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
명령형
const ul = document.createElement('ul');
items.forEach((item) => {
const li = document.createElement('li');
li.textContent = item.name;
ul.appendChild(li);
});
document.body.appendChild(ul);
Q. 리액트가 예측가능한 UI를 만들기 위해 어떤 것들을 하고 있어?
A.
1. 단방향 데이터 흐름 (State → UI)
리액트는 항상 상태(state)를 기반으로 UI를 구성한다.
상위에서 하위로만 흐르는 단방향 데이터 흐름으로 상태가 바뀌면 리액트가 알아서 re-render를 한다.
2. 불변성(immutability) 유지
상태를 직접 바꾸지 않고 항상 새로운 상태를 만들어서 업데이트 한다.
불변성을 지켜야 리액트가 변화 감지를 정확히 하고 UI를 제대로 리렌더 할 수있다.
3. Pure Component와 Side Effect 분리
리액트 컴포넌트는 같은 props와 state를 주면 항상 같은 UI를 렌더해야한다.
이게 Pure Function 기반의 선언적 컴포넌트의 설계 철학이다.
부수효과(Side Effect)는 useEffect 등에서 명시적으로 처리해야한다.
// ❌ 안티패턴: 랜더링 중 데이터 변경
function MyComp() {
fetch('/api/data'); // side-effect — 안 됨
}
4. Key 개념
리스트 렌더링 시 key를 정확히 지정해줘서 리액트가 효율적으로 diffing하고 업데이트 할 수 있도록 해야한다.
key가 예측 가능해야 UI도 예측가능하다.
5. useReducer와 상태 흐름 명확화
복잡한 상태 관리에는 useState보다 useReducer가 더 예측 가능하고 디버깅이 쉽다.
Redux나 Zustand도 같은 원리이다.
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
}
}
6. 리렌더링 최적화 (React.memo, useMemo, useCallback)
예측 가능한 UI는 '불필요한 리렌더링 없음'도 포함되기 때문에 불변성과 함께 최적화 도구를 쓰면 퍼포먼스도 예측 가능하게 유지 가능하다.
반 예측성 요소
항목 | 설명 | 주의점 |
setState() | 비동기 → 다음 렌더 전까지 값 변하지 않음 | 즉시 state 쓰면 안 됨 |
useEffect | 종속성 배열 중요 | 의도치 않은 실행 반복 주의 |
React Strict Mode | 일부 효과 2번 실행됨 (개발모드) | prod에서만 정확히 확인 가능 |
'개념 > 2025 학습' 카테고리의 다른 글
React의 동시성 기능 (Concurrent Features) (0) | 2025.04.24 |
---|---|
자바스크립트 힙 (Heap) (1) | 2025.04.20 |
주요 시간 관련 용어 정리 (UTC, KST, ISO String, Timestamp) (0) | 2025.04.20 |
React 18에서 Strict Mode (0) | 2025.04.20 |
클라이언트에서 API 호출할때 사용하는 도구에는 뭐가 있을까? (fetch, axios, TanStack Query, SWR) + graphql, firebase, supabase (0) | 2025.04.10 |
프로젝트에서 Vue 쓸까? React 쓸까? (0) | 2025.04.06 |
데이터 바인딩(Data Binding)과 MVVM (Vue, React) (0) | 2025.04.06 |
자바스크립트 쓰로틀링(Throttling), 디바운싱(Debouncing) 성능 최적화 (0) | 2025.04.06 |