티스토리 뷰

반응형

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/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Total
Today
Yesterday