훅의 영향력은 데이터 통신이나 폼 관리 같은 복잡한 로직의 영역을 넘어, 애플리케이션의 시각적인 부분을 책임지는 ‘스타일링’ 영역까지 빠르게 확산되었다.
현대적인 웹 애플리케이션에서 ‘다크 모드/라이트 모드’ 전환 기능은 거의 필수가 되어가고 있었다. 이 기능을 구현하기 위해, 개발자들은 보통 리액트의 Context API를 사용하여 현재 테마(‘light’ 또는 ‘dark’)를 전역적으로 공유했다.
하지만 클래스 컴포넌트 시절에는, 이 Context의 값을 사용하는 것이 다소 번거로웠다. <ThemeContext.Consumer>라는 렌더 프롭 패턴을 사용해야만 했다.
이때, styled-components나 Emotion과 같은 주류 CSS-in-JS 라이브러리들이 훅의 흐름에 발 빠르게 동참했다. 그들은 개발자들이 테마 정보에 훨씬 쉽게 접근할 수 있도록, useTheme이라는 이름의 커스텀 훅을 제공하기 시작했다.
이 훅의 내부 구조는 지극히 단순했다.
useContext를 한번 감싼 것에 지나지 않았다.
// 라이브러리 내부 (단순화된 예시)
import { useContext } from 'react';
import { ThemeContext } from './ThemeProvider'; // 라이브러리가 제공하는 Context
export function useTheme() {
// useContext를 사용하여 ThemeContext의 값을 반환한다.
return useContext(ThemeContext);
}
하지만 이 작은 추상화가 가져온 개발 경험의 차이는 엄청났다.
한 디자이너가 개발팀에게, 버튼의 배경색과 글자색이 다크 모드와 라이트 모드에 따라 바뀌어야 한다는 요구사항을 전달했다.
useTheme 훅을 사용하자, 코드는 다음과 같이 간결해졌다.
import styled from 'styled-components';
import { useTheme } from 'styled-components'; // 혹은 Emotion
// styled-components를 사용한 버튼 정의
const StyledButton = styled.button`
background-color: ${props => props.theme.colors.background};
color: ${props => props.theme.colors.text};
padding: 10px 15px;
border: 1px solid ${props => props.theme.colors.border};
cursor: pointer;
`;
function MyButton({ children }) {
// useTheme 훅으로 현재 테마 객체를 가져온다.
const theme = useTheme();
// theme 객체를 styled-component에 prop으로 전달한다.
return <StyledButton theme={theme}>{children}</StyledButton>;
}
이전처럼 <Consumer>로 코드를 감쌀 필요가 전혀 없었다.
const theme = useTheme();
이 한 줄의 코드로, 어떤 컴포넌트에서든 현재 활성화된 테마 객체(색상, 폰트 크기, 간격 등)에 손쉽게 접근할 수 있게 된 것이다.
이제 애플리케이션 최상단에서 테마를 전환하면, useTheme 훅을 사용하는 모든 컴포넌트가 동시에 리렌더링되며 새로운 스타일에 맞춰 자신의 모습을 바꿨다.
useTheme 훅은 useContext의 가장 훌륭하고 실용적인 활용 사례 중 하나였다. 그것은 훅이 어떻게 기존의 리액트 기능(Context)을 더욱 강력하고 사용하기 쉽게 만드는지를 명확히 보여주었다.
또한, 이것은 커스텀 훅의 중요한 철학을 다시 한번 일깨워주었다.
‘복잡성을 숨기고, 의도를 드러내라.’
개발자는 더 이상 useContext(ThemeContext)라는 구체적인 구현에 대해 알 필요가 없었다. 그저 useTheme이라는, 의도가 명확한 이름의 훅을 호출하기만 하면 되었다.
훅은 리액트 애플리케이션의 로직과 스타일링 사이의 경계를 허물고 있었다.
데이터와 UI, 그리고 스타일이 훅이라는 공통된 언어를 통해 유기적으로 연결되기 시작했다.
하지만 useContext를 전역 상태 관리의 만병통치약으로 사용하려던 개발자들은, 곧 이 편리함 뒤에 숨겨진 미묘한 성능 문제와 마주하게 될 터였다. 그 문제는 커뮤니티가 Redux와 Context의 장점만을 취한, 새로운 형태의 상태 관리 솔루션을 모색하게 만드는 계기가 되었다.


