티스토리 뷰
오늘은 Jōtai 상태 관리 라이브러리에 대해 간단하게 정리해 보려고 한다. 사용방법보다는 공부하면서 새롭게 알게 된 내용이나 중요한 개념을 위주로 다루어 보려고 한다.
많은 상태 관리 라이브러리가 존재하지만, Jōtai를 선택한 이유는 이번 프로젝트에서 전역적으로 관리할 데이터가 많지 않았기 때문이다. Jōtai는 가벼운 상태 관리 라이브러리로, 필요에 따라 간편하게 상태를 정의하고 사용할 수 있다. 특히, 일부 페이지에서 필요한 데이터를 가져오거나 전역 모달을 처리하는 용도로 사용하기에 효율적일 수 있다고 생각했다.
Jōtai(조타이)는 bottom-up 접근법으로 작은 단위의 상태(atom)를 위로 전파할 수 있는 구조를 가진다. 또한, Context API와 달리 전역 상태가 변경될 때, 관련이 없는 컴포넌트의 리렌더링이 발생하지 않게 설계되었다. 즉, 상태가 직접적으로 의존하고 있는 컴포넌만 리렌더링이 발생함으로 성능면에서 효율적이다.
atom 함수는 atom의 config를 생성할 때 사용한다. atom의 config는 불변 객체이다. 아래와 같이 초기값을 제공하여 사용한다.
import { atom } from 'jotai'
const priceAtom = atom(10);
const messageAtom = atom('hello');
const productAtom = atom({ id: 12, name: 'good stuff' });
또한, 아래와 같이 derived atoms도 생성할 수 있다.
아래 코드는 각각 Jōtai에서의 읽기 전용, 쓰기 전용, 읽기 및 쓰기에 대한 예제 코드이다.
readOnlyAtom은 부모 atom의 값을 참조하여, 필터링이나 정렬이 필요한 데이터에 사용했다. 예를 들어, 전체 데이터셋에서 요일별로 필터링하거나 회원 유형에 따른 데이터 필터링에 활용할 수 있다. 이러한 방식으로 특정 조건에 맞는 데이터를 효율적으로 처리할 수 있다.
// priceAtom(부모)에 의존한다. readOnlyAtom은 직접 값을 바꿀 수 없다.
const readOnlyAtom = atom((get) => get(priceAtom) * 2);
writeOnlyAtom은 특정 상태의 업데이트만을 처리하는 atom으로, 직접적인 값을 반환하지는 않는다.
const writeOnlyAtom = atom(
null,
(get, set, update) => {
set(priceAtom, get(priceAtom) - update.discount)
set(priceAtom, (price) => price - update.discount)
},
);
마지막으로 readWriteAtom은 읽기와 쓰기가 모두 가능한 atom으로, 값을 참조하고 동시에 업데이트하는 기능을 수행한다.
const readWriteAtom = atom(
(get) => get(priceAtom) * 2,
(get, set, newPrice) => { set(priceAtom, newPrice / 2); },
);
마지막으로 위에서 사용된 get / set / update 함수에 대해 간단하게 정리해보자.
- get 함수 : atom의 값을 읽는데 사용한다. atom의 값을 읽을 때, 해당 atom의 의존성을 추적한다. 이로 인한 상태 변경시, 상태를 사용하는 컴포넌트가 자동으로 리렌더링된다.
- set 함수 : atom의 값을 업데이트할 때 사용한다. 단순히 새로운 값을 전달할 수 있고, 함수형 업데이트를 통해 현재 상태를 기반으로 변경할 수 있다.
- update : write함수에서 atom의 상태를 업데이트할 때 전달되는 인자이다. 다양한 형태로 전달될 수 있다.
useAtom 훅은 이러한 atom을 읽고 업데이트하는 데 사용된다. React의 useState와 같이 atom 값을 업데이트하는 함수를 반환한다.
const [value, setValue] = useAtom(anAtom);
// USE
const Page = () => {
const [message, setMessage] = useAtom(messageAtom);
const handleOnClickButton = () => setMessage("click button!");
return (
<div>
<h1>{message}</h1>
<button onClick={handleOnClickButton}></button>
</div>
);
};
useAtom 훅이 관리하는 atom(애플리케이션의 상태를 관리하는 가장 작은 단위)의 상태는 atom configs(atom을 생성하기 위한 설정 객체, 초기값등 정의)와 atom values(실제로 atom이 가지고 있는 상태 값)간의 관계를 의미한다. 이는 WeakMap이라는 자료구조로 관리된다.
Jotai는 내부적으로 WeakMap을 사용하여, Atom 상태를 관리한다. 아래 내용은 Jotai 공식 문서의 일부 내용이다.
Let's start with an easy example. An atom is just a function that will return a configuration object. We are using WeakMap to map atom with their state. WeakMap doesn't keep its keys in memory, so if an atom is garbage collected, its state will be garbage collected too. This helps avoid memory leaks.
간단하게 WeakMap에 대해 정리하자면, Map과 같이 key-value로 이루어진 객체이다. 이 둘의 차이를 정리해보자.
1. Map과 달리 WeakMap은 key타입이 객체만 가능하다.(원시값이 될 수 없음)
2. WeakMap은 key가 더 이상 참조되지 않을 때, 자동으로 GC에 의해 메모리에서 정리된다. (언제 삭제되는지 알 수 없음)
3. WeakMap은 요소를 순회하거나 key 또는 value 목록을 조회하는 메서드 자원이 없다. (get / set / has / delete만 존재함)
"WeakMap은 요소를 순회하거나 key 또는 value 목록을 조회하는 메서드 자원이 없다"는 이유는 WeakMap의 설계 원리와 관련이 있다. WeakMap의 주요 특징 중 하나는 메모리 누수를 방지하기 위해 key 객체에 대한 강한 참조를 생성하지 않는다는 점이다. key가 더 이상 필요 없을 때, 자바스크립트 엔진은 그 객체를 GC 대상으로 만들 수 있다. 이러한 이유로 WeakMap은 그 내부 요소를 순회하는 방법이나 key/value 목록을 조회하는 기능을 제공하지 않는다.
만약 WeakMap이 요소를 순회하거나 key/value 목록을 조회하는 메서드를 제공한다면?
key/value 목록을 조회하는 메서드를 호출 했을 때, 그 순간에는 해당 객체가 존재하더라도 GC에 의해 해당 객체가 사라질 수 있기 때문에 조회 결과 예측이 어려운 상태가 된다. 이로 인해 신뢰할 수 있는 key/value 목록을 보장받지 못하게 된다. 또한, WeakMap의 비결정성이라는 특징 때문에 어떤 key/value가 언제 삭제될지 알 수 없다. 결과적으로, WeakMap은 메모리 관리에 유리하지만, 데이터를 순회하거나 조회할 수 있는 방법이 없기 때문에 특정 사용 사례에 제한적일 수 있다.
- Total
- Today
- Yesterday