React 목록으로

남이 짠 코드 읽는 법(React)

React

들어가며

AI가 코드를 짜주는 시대가 됐다. 그런데 막상 받아보면 당황스럽다. 코드는 동작하는데 무슨 일이 일어나는지 모르겠고, 수정하려니 어디를 건드려야 할지 모르겠다. 위에서부터 한 줄씩 읽기 시작하면 중간에 막히고, 전체 맥락을 잡지 못한 채 부분만 보게 된다.

이 글은 AI가 생성한 React 컴포넌트를 효율적으로 읽는 순서를 정리한다. 예시는 D3와 Framer Motion을 사용하는 실제 BarChart 컴포넌트다. 모르는 라이브러리가 나와도 읽는 방법은 동일하다.


기본 원칙 : 위에서부터 읽지 않는다.

코드를 처음 받으면 본능적으로 1번 줄부터 읽기 시작한다. 하지만 React 컴포넌트는 위에서 아래로 읽는 글이 아니다. 읽는 순서가 따로 있다.

경계 → 상태 → 부수효과 → 렌더링

이 순서로 읽으면 전체 구조가 먼저 잡히고, 세부 내용은 그 안에 채워진다.


1단계 : 경계를 먼저 찾는다.

컴포넌트가 뭘 받고 뭘 내보내는지 먼저 파악한다. Props 인터페이스와 return 문 두 가지만 보면 된다.

TSX
1interface BarChartProps { 2 data: ChartDatum[]; 3 animationKey?: string; 4}

dataanimationKey를 받는다. animationKey는 옵셔널이다. 여기서 "왜 animationKey가 있을까?"라는 질문은 잠시 보류한다. 나중에 자연스럽게 답이 나온다.

다음으로 return 문의 최상위 구조만 본다. 세부 내용은 건너뛴다.

TSX
1return ( 2 <div ref={containerRef}> 3 <svg> 4 {/* 차트 내용 */} 5 </svg> 6 {tooltip && <div>...</div>} 7 </div> 8)

div안에 svg가 있고, tooltip이 있을 때만 툴팁 div가 렌더된다. 이것만 파악해도 이 컴포넌트가 "SVG 차트 + 조건부 툴팁"이라는 구조가 보인다.

여기까지 30초. 컴포넌트가 하는 일의 70%가 파악된다.


2단계 : 상태 목록을 라벨링한다.

useState를 전부 찾아서 각각 무슨 역할인지 한 줄로 정리한다.

TSX
1const [tooltip, setTooltip] = useState<TooltipState | null>(null); 2// → 호버 중인 막대의 툴팁 데이터. null이면 툴팁 숨김 3 4const [width, setWidth] = useState(W_MIN); 5// → 컨테이너의 현재 너비. 반응형 대응용

상태가 두 개뿐이다. 이 컴포넌트가 관리하는 동적인 값은 "툴팁 표시 여부"와 "현재 너비" 딱 두 가지다. 복잡해 보이는 코드도 상태 목록을 먼저 보면 의외로 단순하다.


3단계 : useEffect를 분류한다

useEffect가 여러 개면 각각 왜 존재하는지를 분류한다. 의존성 배열이 핵심 단서다.

TSX
1useEffect(() => { 2 // ResizeObserver 등록 3}, []); // 빈 배열 → 마운트 시 1회 실행
TSX
1useEffect(() => { 2 // D3 axis 렌더링 3}, [x, y]); // x, y 변경 시 재실행

첫 번째는 컴포넌트가 처음 마운트될 때 한 번만 실행되는 초기화 코드다. 두 번째는 스케일이 바뀔 때마다 축을 다시 그리는 코드다. 내용을 몰라도 의존성 배열만 보면 "언제 실행되는가"는 바로 파악된다.


4단계 : 모르는 함수는 입출력만 파악한다.

AI 코드에는 모르는 라이브러리 함수가 자주 등장한다. 내부 구현을 파고들 필요 없이 "뭘 넣으면 뭐가 나오는가" 만 파악한다.

TSX
1const x = d3 2 .scaleBand() 3 .domain(filteredData.map((d) => d.category)) // 입력: ['식비', '교통', '쇼핑'] 4 .range([0, innerW]) // 출력 범위: 0 ~ 실제 px 5 .padding(0.45);

d3.scaleBand()가 뭔지 몰라도 된다. "카테고리 이름을 넣으면 x좌표 픽셀값이 나오는 함수"라는 것만 알면 이후 코드를 읽을 수 있다. 실제로 아래에서 이렇게 사용된다.

TSX
1x={x(d.category) ?? 0} // '식비' → 0, '교통' → 120, ... 2width={x.bandwidth()} // 막대 너비 자동 계산

5단계 : return 안에서 데이터 흐름을 역추적한다.

마지막으로 렌더링 코드에서 각 값이 어디서 왔는지 연결한다.

TSX
1<motion.rect 2 key={`${animationKey}-${d.category}`} // ← props에서 받은 animationKey 3 x={x(d.category) ?? 0} // ← 4단계에서 파악한 x 스케일 함수 4 width={x.bandwidth()} // ← scaleBand 자동 계산값 5 initial={{ y: innerH, height: 0 }} // ← 애니메이션 시작 상태 6 animate={{ y: barY, height: barHeight }} // ← 실제 좌표값 7/>

여기서 아까 보류했던 질문 "왜 animationKey가 있을까?"의 답이 나온다. key가 바뀌면 React가 컴포넌트를 다시 마운트하고, Framer Motion이 initial부터 애니메이션을 재실행한다. animationKey prop은 바깥에서 애니메이션을 다시 트리거하기 위한 장치였다.


마치며

위에서 아래로 읽으면 모르는 게 나올 때마다 막힌다. 이 순서대로 읽으면 전체 구조를 먼저 잡고 세부로 들어간다. AI가 짜준 코드든, 동료가 짜준 코드든 읽는 방법은 동일하다.

모르는 부분이 있다면 그 부분만 잘라서 AI에게 물어보는 것도 좋은 방법이다. "이 useEffect가 왜 있어?", "이 key prop이 하는 역할이 뭐야?" 처럼 좁고 구체적인 질문일수록 더 명확한 답이 돌아온다.