첫 코드, Zustand의 태동
제7화
발행일: 2025년 05월 09일
주말이었다. 평일의 치열했던 전투, 즉 버그와의 씨름과 비효율적인 코드와의 싸움으로 지친 개발자들에게는 달콤한 휴식이 주어지는 시간. 하지만 다이시 카토에게 이번 주말은 달랐다. 그의 머릿속을 가득 채운 새로운 아이디어, ‘선택적 구독을 갖춘 외부 스토어’라는 영감은 그의 손가락을 근질거리게 만들었다.
“후… 해보자.”
토요일 아침, 카토는 평소보다 일찍 눈을 떴다. 창밖은 아직 어둑했지만, 그의 눈빛만은 형형하게 빛나고 있었다. 커피 한 잔을 옆에 두고, 그는 익숙하게 코드 에디터를 열었다. 텅 빈 화면. 이곳에 그는 기존의 문제들을 해결할 새로운 세계를 창조할 참이었다.
목표는 명확했다. 지난 며칠간 머릿속으로 수없이 되뇌었던 네 가지 핵심 원칙.
하나. 최소한의 코드. 보일러플레이트는 질색이다. 개발자는 핵심 로직에 집중해야 한다.
둘. 직관적인 훅 API. useState
처럼 쉽고 간결하게. React 개발자라면 누구나 금방 익숙해질 수 있어야 한다.
셋. Context 문제 해결. 불필요한 렌더링은 이제 그만. 선택적 구독으로 성능을 극대화한다.
넷. 미래 기술 호환성. 당장은 아니더라도, React의 Concurrent Mode 같은 차세대 기술과도 문제없이 동작해야 한다.
그의 손가락이 키보드 위에서 춤을 추기 시작했다. 먼저 스토어를 생성하는 함수 create
. 외부 스토어의 기본 골격을 잡는 작업이었다. 상태를 저장하고, 상태를 변경하는 함수(setter)를 제공하는 단순하지만 강력한 구조.
// 초기 구상 스케치 (실제 코드와는 다를 수 있음)
function create(createState) {
let state;
const listeners = new Set();
const setState = (partial) => {
const nextState = typeof partial === 'function' ? partial(state) : partial;
if (nextState !== state) {
state = Object.assign({}, state, nextState);
// 리스너들에게 알림! (아직은 전체 알림)
listeners.forEach((listener) => listener());
}
};
const getState = () => state;
const subscribe = (listener) => {
listeners.add(listener);
// 구독 해제 함수 반환
return () => listeners.delete(listener);
};
state = createState(setState, getState); // 초기 상태 설정
// 스토어 API 반환 (훅에서 사용될 것들)
return { setState, getState, subscribe };
}
핵심은 ‘선택적 구독’을 어떻게 훅과 자연스럽게 연결하느냐였다. 그는 useStore
라는 이름의 커스텀 훅을 구상했다. 이 훅은 스토어와 함께 ‘셀렉터(selector)’ 함수를 인자로 받는다. 셀렉터 함수는 전체 상태 객체에서 컴포넌트가 실제로 필요한 데이터 조각만을 추출하는 역할을 한다.
// useStore 훅의 초기 구상
function useStore(store, selector) {
// 현재 상태에서 필요한 부분만 가져옴
const selectedState = selector(store.getState());
// 상태가 변경될 때마다 셀렉터로 다시 계산하고,
// 이전 값과 다를 경우에만 리렌더링을 트리거!
// (이 부분이 핵심 로직)
const [state, forceUpdate] = useState(selectedState);
useEffect(() => {
const unsubscribe = store.subscribe(() => {
const nextSelectedState = selector(store.getState());
if (nextSelectedState !== state) {
// 비교!
forceUpdate(nextSelectedState); // 다르면 리렌더링!
}
});
return unsubscribe;
}, [store, selector, state]); // 의존성 배열 관리도 중요
return state;
}
코드를 짜내려 갈수록 그의 머릿속은 더욱 명료해졌다. 복잡한 의존성 주입 라이브러리나 거창한 프레임워크 없이, 오직 순수 자바스크립트와 React 훅의 조합만으로 이 모든 것을 구현할 수 있다는 사실에 스스로도 놀랐다.
“좋아… 아주 좋아.”
기본적인 구조가 잡혀가자, 그는 잠시 숨을 골랐다. 이제 이 녀석에게 이름을 붙여줄 차례였다. 프로젝트 이름? 코드 네임? 아니, 좀 더 본질적인 이름이 필요했다. 이 라이브러리의 핵심은 결국 ‘상태(State)’를 다루는 것이었다.
그는 문득 간결하고 명료한 느낌의 독일어가 떠올랐다. 검색창에 ‘state’를 입력하고 독일어 번역을 찾았다.
‘Zustand (추스탄트)’
발음하는 순간, 입에 착 달라붙는 느낌. 간결하면서도 핵심을 찌르는 단어. 마치 자신이 만들고자 하는 라이브러리의 철학과 닮아 있었다.
“좋았어. 너의 이름은 Zustand다.”
카토는 만족스러운 미소를 지으며 package.json
파일에 그 이름을 새겨 넣었다.
주말 동안 그는 미친 듯이 코딩에 몰두했다. 기본적인 기능 구현, 간단한 테스트 케이스 작성. 아직은 거칠고 다듬어야 할 부분이 많았지만, 프로토타입은 분명히 작동했다. Context API의 문제점을 해결하고, useState
처럼 간결한 사용성을 제공하는 새로운 상태 관리 솔루션의 가능성이 눈앞에 펼쳐졌다.
해가 지고 다시 밤이 깊어갈 무렵, 카토는 마침내 키보드에서 손을 뗐다. 온몸은 뻐근했지만, 마음만은 날아갈 듯 가벼웠다. Zustand. 이제 막 세상에 태어난 이 작은 씨앗이 앞으로 어떻게 자라날지, 어떤 폭풍우를 만나고 또 어떤 꽃을 피우게 될지, 그는 알 수 없었다.
하지만 한 가지는 확실했다. 이 작은 씨앗은 분명, React 상태 관리라는 척박한 땅에 새로운 희망을 심고 있었다. 카토는 창밖의 어둠 속에서 다가올 미래를 그리며, 다시 한번 조용히 되뇌었다.
“Zustand…”
그의 새로운 여정이 막 시작되고 있었다.