Jotai, 첫 번째 코드 라인
제6화
발행일: 2025년 05월 18일
주말의 고요함이 내려앉은 다이시 카토의 작업 공간. 창밖은 아직 푸른빛이 감돌았지만, 그의 책상 위 스탠드 불빛은 이미 오래전부터 깨어 있었다. 아토믹 스테이트, 파생된 상태로서의 함수… 지난 며칠간 그의 머릿속을 휘감았던 이 매혹적인 아이디어들은 이제 더 이상 추상적인 개념으로만 머무를 수 없었다.
이론의 아름다움은 현실의 코드로 증명되어야만 진정한 가치를 발하는 법.
“시작해보자.”
카토는 낮게 읊조리며 새로운 프로젝트 폴더를 생성했다. 텅 빈 디렉토리 구조. 마치 태초의 혼돈처럼, 이곳에 그는 상태 관리의 새로운 질서를 세울 참이었다. 그의 손가락이 경쾌하게 키보드 위를 두드리기 시작했다.
가장 먼저 생명을 불어넣어야 할 것은 역시 atom()
함수였다. 상태 원자를 정의하는 가장 근본적인 빌딩 블록. 거창한 구조나 복잡한 설정은 필요 없었다. 최대한 간결하게, 원자의 본질을 담아내는 것이 중요했다.
// atom 함수의 초기 프로토타입 스케치
let atomIdCounter = 0;
function atom(initialValue) {
const config = {
id: `atom_${atomIdCounter++}`, // 각 아톰을 식별할 고유 ID (나중엔 WeakMap 등 활용 고려)
init: initialValue, // 초기값 저장
// 여기에 상태를 읽고 쓰는 로직, 구독 관리 로직 등이 추가될 것...
};
// 아톰 설정을 반환 (이것이 아톰의 '실체')
return config;
}
코드는 단순했다. 하지만 그 안에는 상태를 독립적인 단위로 취급하겠다는 강력한 철학이 담겨 있었다. 각 atom()
호출은 세상에 단 하나뿐인 고유한 상태 조각을 탄생시키는 행위였다.
다음은 이 원자들을 React 컴포넌트와 연결하는 다리, useAtom()
훅이었다. Zustand의 useStore
가 셀렉터 함수를 요구했던 것과 달리, 이 훅은 원자 설정 객체 자체를 인자로 받아야 했다. 그리고 그 원자의 현재 값을 반환하고, 값을 변경할 수 있는 함수를 제공해야 했다.
// useAtom 훅의 초기 프로토타입 스케치
function useAtom(atomConfig) {
// 스토어(혹은 컨텍스트)에서 해당 아톰의 현재 값을 읽어옴
const [value, setValue] = useState(() => /* 스토어에서 초기값 읽기 로직 */);
// 아톰 값이 변경될 때 컴포넌트를 리렌더링하는 구독 로직 필요
useEffect(() => {
const unsubscribe = /* 스토어에 구독하고 값 변경 시 setValue 호출하는 로직 */;
return unsubscribe;
}, [atomConfig.id]); // 아톰 ID로 구독 관리
// 상태 값과 상태 변경 함수 반환
const setAtom = (update) => {
// 스토어에 값 변경 요청 보내는 로직
};
return [value, setAtom];
}
구현은 아직 거칠었다. 실제 상태 저장 및 구독 메커니즘은 더 정교하게 다듬어져야 했다. 하지만 기본적인 틀은 잡혔다. atom()
으로 상태 조각을 정의하고, useAtom()
으로 컴포넌트에서 직접 사용하는 것. 셀렉터 함수 없이, 더 직관적으로 상태에 접근하는 방식.
카토는 간단한 카운터 예제를 작성하여 이 프로토타입을 테스트했다.
const countAtom = atom(0); // 초기값 0인 카운터 아톰 정의
function Counter() {
const [count, setCount] = useAtom(countAtom); // countAtom 사용
return (
<div>
<span>Count: {count}</span>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
</div>
);
}
떨리는 마음으로 브라우저에서 코드를 실행하고 버튼을 클릭했다.
‘제발…’
화면의 숫자가 ‘0’에서 ‘1’로, 다시 ‘2’로 부드럽게 증가했다.
“됐다!”
카토는 자신도 모르게 짧은 탄성을 내뱉었다. 작동했다! 비록 가장 기본적인 형태였지만, 아토믹 스테이트라는 개념이 현실의 코드로 구현될 수 있다는 가능성을 확인한 것이다. 그의 심장이 다시 한번 빠르게 뛰었다.
이제 이 새로운 창조물에게 이름을 붙여줄 시간이었다. Zustand가 ‘상태’를 의미하는 독일어였듯, 이번에도 그 본질을 담고 싶었다. 그는 자연스럽게 자신의 모국어인 일본어를 떠올렸다.
‘상태… 상태는 일본어로…’
状態 (じょうたい - Jōtai)
발음하는 순간, 입에 착 감기는 느낌. 간결하면서도 울림이 있었다. Zustand와 뿌리는 같지만(둘 다 ‘상태’를 의미하지만), 전혀 다른 언어, 다른 문화권의 느낌. 마치 그가 만들고자 하는 라이브러리의 철학처럼, 근본은 같지만 접근 방식과 표현은 완전히 새로운.
“좋아. 너의 이름은 Jotai(조타이)다.”
그는 새로 만든 package.json
파일에 그 이름을 새겨 넣었다. 마치 새로운 생명에게 이름을 부여하는 의식처럼 경건한 마음이었다.
Jotai. 이제 막 첫 숨을 내쉰 작은 라이브러리. Zustand라는 거대한 형의 그늘 아래에서 태어났지만, 분명 다른 운명을 향해 나아갈 존재였다. 카토는 Jotai의 코드를 바라보았다. 이것은 Zustand의 연장선이 아니었다. 전혀 다른 종류의 짐승, 다른 종류의 가능성이었다.
그의 손끝에서 시작된 첫 코드 라인. 그것은 React 상태 관리 역사에 또 다른 변곡점을 가져올 미세한 지진의 시작일지도 몰랐다. 앞으로 어떤 거대한 산맥을 넘어야 할지, 어떤 예상치 못한 강을 건너야 할지 알 수 없었지만, 카토의 눈빛에는 새로운 도전을 향한 설렘과 투지가 가득했다. Jotai의 이야기는 이제 막 첫 페이지를 넘기고 있었다.