React 밖으로 나가는 탈출구: ref와 Effect
React 밖으로 나가는 탈출구: ref와 Effect
React가 다루는 화면 안에서는 대부분 해결되지만, React 바깥의 시스템을 제어해야 할 때가 있어요 — 브라우저 API로 입력창에 포커스를 준다거나, React 없이 만든 영상 플레이어를 멈추고 재생한다거나, 원격 서버의 메시지를 듣는 일이죠. 이런 경우를 위해 React가 마련해 둔 '밖으로 나가는 탈출구'가 바로 ref와 Effect예요. 다만 이들은 정말 필요할 때만 쓰는 도구라서, 앱의 핵심 로직이 여기에 의존하도록 설계하는 건 피해야 해요.
ref로 값 기억하고 DOM 건드리기
컴포넌트가 값을 기억해야 하는데, 그 값이 렌더링을 다시 일으키면 안 될 때가 있어요. 그럴 땐 state 대신 ref를 써요.
const ref = useRef(0);
ref의 내부 값(ref.current)을 바꿔도 렌더링이 다시 일어나지 않아요. 그럼 왜 ref가 필요할까요? React가 관리하는 DOM 요소에 직접 접근해야 할 때예요. 포커스를 주거나, 스크롤을 이동하거나, 크기를 측정하는 일은 React 기본 문법으로는 할 수 없는데, DOM 노드를 ref에 연결해 두면 그런 조작이 가능해져요.
Effect로 외부 시스템과 동기화하기
이벤트 핸들러가 특정 이벤트에만 반응한다면, Effect는 렌더링이 끝난 뒤 코드를 실행해서 외부 시스템과 컴포넌트를 동기화해요. React가 아닌 컴포넌트를 state에 맞춰 제어하거나, 서버 연결을 맺거나, 컴포넌트가 화면에 나타났을 때 분석 로그를 보내는 용도로 써요. useEffect에는 동기화 시작 로직과 함께 정리(cleanup) 함수를 함께 적게 되는데, 개발 모드에서는 React가 이 Effect를 한 번 더 실행·정리하면서 정리 함수를 빼먹지 않았는지 검사해요.
Effect의 수명주기도 컴포넌트와 달라요. 컴포넌트는 마운트·업데이트·언마운트를 거치지만, Effect가 할 수 있는 일은 '동기화 시작'과 '동기화 정지' 두 가지뿐이에요. 의존성 배열에 적힌 값(props·state 같은 reactive 값)이 바뀌면 Effect는 다시 동기화(재연결)돼요. React가 제공하는 린터 규칙이 이 의존성 목록을 제대로 적었는지 잡아주니, 의존성을 임의로 선택하기보다 코드에 쓰인 reactive 값을 그대로 나열한다고 이해하는 게 맞아요.
재사용 로직은 커스텀 Hook으로
React에는 useState, useContext, useEffect 같은 내장 Hook이 있지만, 데이터 fetch라든가 '사용자가 온라인인지 추적' 같은 더 구체적인 목적을 위한 Hook이 있으면 좋겠다고 느낄 때가 있어요. 그럴 때는 직접 커스텀 Hook을 만들면 돼요. 예를 들면 커서 위치를 추적하는 usePointerPosition 같은 Hook을 정의해 두면, 컴포넌트 간에 로직을 조합·재사용할 수 있어요. 커스텀 Hook이 늘어나면 손으로 쓰는 Effect 수도 그만큼 줄어들어요.
더 알아보기
- ref로 값 참조하기 — 상태와 ref의 차이를 정리해 둔 페이지예요
- Effect로 동기화하기 — Effect의 사용례를 본격적으로 다뤄요
- Effect가 필요 없을 수도 있어요 — 불필요한 Effect를 걷어내는 판단 기준을 배워요