← 전체 글로 돌아가기

Next.js

React 컴포넌트가 너무 커졌을 때 나누기

컴포넌트를 나눌 때는 상태와 렌더링을 먼저 분리하고, 실제 재사용성을 고려해야 한다.

React에서 한 파일에 모든 로직을 때려박으면, 코드가 복잡해지고 수정할 때마다 예상 밖의 버그가 생긴다. 특히 상태 관리와 렌더링이 뒤섞여 있으면 문제를 찾기 힘들다.

핵심은 컴포넌트를 작게 나누는 것 자체가 아니라, 무엇을 기준으로 나눌지 생각하는 것이다.

먼저 현재 상태 파악

컴포넌트의 state가 몇 개인지, 각 state가 어디에서 쓰이는지 정리한다. 로그를 찍거나 React DevTools로 확인하면 된다.

// 컴포넌트 내부 state 확인
const [formData, setFormData] = useState({})
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [data, setData] = useState([])

렌더링과 상태 관리 분리

컴포넌트를 둘로 나눈다. 상태만 관리하는 Custom Hook과, 상태를 받아서 UI만 그리는 프레젠테이션 컴포넌트로 나눈다.

// useFormLogic.ts - 상태 관리만
const useFormLogic = () => {
  const [formData, setFormData] = useState({})
  const [loading, setLoading] = useState(false)
  return { formData, setFormData, loading, setLoading }
}

// FormUI.tsx - UI만
const FormUI = ({ formData, loading }) => (
  <div>...</div>
)

같은 책임끼리 묶기

컴포넌트의 부분별로 역할을 보고, 같은 책임을 가진 부분끼리 새로운 컴포넌트로 분리한다. 예를 들어 폼 입력 부분, 결과 표시 부분, 에러 처리 부분을 따로 컴포넌트로 뺀다.

// 각각 독립적인 역할
<FormInputs />
<ResultDisplay />
<ErrorMessage />

Props drilling 피하기

Props를 너무 깊게 파고 내려가면 컴포넌트 간 결합도가 높아진다. Context나 상태 관리 라이브러리 사용을 고려한다.

모바일과 데스크톱 뷰 분리

데스크톱과 모바일 레이아웃이 크게 다르다면, 조건부 렌더링보다는 별도의 컴포넌트로 나누는 게 낫다.

// 화면 크기에 따라 다른 컴포넌트
const isMobile = useMediaQuery('(max-width: 768px)')
return isMobile ? <MobileForm /> : <DesktopForm />

실제 재사용 여부 확인

나눈 컴포넌트가 정말 재사용될지 확인한다. 한 곳에서만 쓰이는 컴포넌트로 나누면 오히려 코드가 복잡해질 수 있다.

개발 환경에서 상태 변화 추적

React DevTools로 각 컴포넌트의 props와 state 변화를 실시간으로 추적하면서 나눠진 컴포넌트들이 제대로 동작하는지 본다.

  1. 컴포넌트의 state와 렌더링 로직을 먼저 분석한다.
  2. 상태 관리를 Custom Hook으로 빼낸다.
  3. 남은 렌더링 로직을 더 작은 프레젠테이션 컴포넌트로 나눈다.
  4. Props drilling이 없는지 확인한다.

마지막 확인

컴포넌트를 나눈 후에는 각 컴포넌트가 독립적으로 작동하는지 테스트해야 한다. 로컬에서 완전히 재현 가능한 상태로 만들어두면 다음에 같은 컴포넌트를 수정할 때도 빨리 찾을 수 있다.