Jotai 로 상태 관리하기 (Jotai 사용법)
서론
열심히 리액트 스터디 중이던 인피덕,
회사에서 사용할 프론트 기술 스택을 논의하다 최종적으로 Next.js
와 Jotai
가 결정되는데…
인생 처음 접해보는 라이브러리와 프레임 워크를 정리해 보도록 하자.
Jotai 를 사용하는 방법 (공식 문서 발췌)
-
initalValue
로 간단하게 만들기 -
read
용으로 만들기 -
write
용으로 만들기 -
read
,write
모두 가능하게 만들기
Jotai
를 검색했을 때 뜨는 글들이 거의 다 비슷한 내용이라 내 입맛대로 정리하기 위해 몇 자 적어본다.
스터디 중이라 틀린 부분이 있을 수 있으니 발견하시면 댓글 남겨주시기 바랍니다.
조타이가 조타잉~ 이라고 외치는 여러분이 되시길 바랍니다. 물론 저 부터…
본론
안녕하세요, 처음 뵙겠습니다. atom
atom
이란 녀석을 사용해서 선언
import React from "react";
import { atom, useAtom } from "jotai";
// atom 이라는 녀석으로 countAtom 이라는 atom value 를 하나 만들어 준다.
const countAtom = atom(0);
const App = () => {
// 만든 countAtom 녀석을 useAtom 이라는 친구를 활용해 우리가 사용할 수 있도록 만들어 준다.
// 튜플로 받는 이유: useAtom 이 튜플로 리턴함 (첫번째: 값, 두번째: 값 set 하는 친구)
// 형식이 리액트의 setState 와 거의 매우 완전 대박 비슷
const [count, setCount] = useAtom(countAtom);
return (
<>
몇번 눌렀을까?: {count}
<br />
<button onClick={() => setCount((prev) => prev + 1)}>눌러보아라</button>
</>
);
};
export default App;
예제로 정말 아주 기본적이고 많이 사용되는 카운터를 만들어 보았다.
저 코드 그대로 복붙해서 실행해 보면 이상없이 count
가 1 씩 증가되는 걸 볼 수 있다.
사실 조타이 찾아볼 때 대부분의 예제가 카운터 예제라서 새로운 내용으로 만들어 보자 했는데 카운터로 만듦 ㅎ
atom 으로 값을 세팅할 때 가능한 애들
atom
으로 state
만들 때 값은 뭐뭐 넣을 수 있어요?
다 가능
...
const numAtom = atom(12);
const strAtom = atom("str");
const arrAtom = atom([1, 2, 3]);
const objAtom = atom({ name: "infiduk", blog: "https://infiduk.github.io/" })
...
조타이 신기한 점
(내가 리액트 state
관리를 제대로 못 해봐서 다른 상태 관리 라이브러리에도 있는 기능일 수 있지만) 조타이에는 read only
, write only
를 위한 atom
을 만들 수 있는 신기한 기능이 있다고 한다.
기본적인 atom
정의
초기 값만 받아서 초기 값과 set
하는 친구를 리턴
export declare function atom<Value>(
initialValue: Value
): PrimitiveAtom<Value> & WithInitialValue<Value>;
useAtom
정의
atom
의 값과 해당 atom
을 어느 범위까지 사용할 건지 보내고(optional), 해당하는 값과 값을 set
하는 함수를 리턴
export declare function useAtom<
Value,
Update,
Result extends void | Promise<void>
>(
atom: WritableAtom<Value, Update, Result>,
scope?: Scope
): [Awaited<Value>, SetAtom<Update, Result>];
getter 용도로만 쓰기
아까 위의 코드를 복붙해 만들어 봤던 카운터 예제를 활용해서 테스트 해 보자.
먼저 get
을 활용한 예제부터 보도록 하자.
import React from "react";
import { atom, useAtom } from "jotai";
const countAtom = atom(0);
// atom 의 getter 를 활용해서 countAtom * 2 를 가져오는 녀석을 만들어 봤다.
const doubleCountAtom = atom((get) => get(countAtom) * 2);
const App = () => {
const [count, setCount] = useAtom(countAtom);
// 위의 countAtom 때와 동일하게 useState 의 역할을 하는 useAtom 이란 녀석으로 값을 가져와 준다.
// 근데 왜 얘는 setDoubleCount 안 받음?
// read only 용이라서 첫번째 리턴 값인 값만 있으면 되어 doubleCount 라는 이름으로 가져옴
// 두번째 리턴 값은 never 형이기 때문에 받고 싶어도 받을 수 없음
const [doubleCount] = useAtom(doubleCountAtom);
return (
<>
몇번 눌렀을까?: {count}
<br />
누른 값 * 2: {doubleCount}
<br />
<button onClick={() => setCount((prev) => prev + 1)}>눌러보아라</button>
</>
);
};
export default App;
atom
을 read only
의 형태로 사용할 때의 정의
read
하는 애만 받고 나도 atom
값만 주겠다.
export declare function atom<Value>(read: Read<Value>): Atom<Value>;
useAtom
정의
atom
과 사용할 범위에 대한 값을 받지만(optional) 값만 리턴 하겠다.
export declare function useAtom<Value>(
atom: Atom<Value>,
scope?: Scope
): [Awaited<Value>, never];
setter 도 안 써보면 섭섭하지
set
을 활용한 예제도 알아보자.
write only
형태로 쓸 때는 어떻게 사용할까?
import React from "react";
import { atom, useAtom } from "jotai";
const countAtom = atom(2);
const doubleCountAtom = atom((get) => get(countAtom) * 2);
// 이 친구는 only set 용이기 때문에 초기 값을 null 로 주고 write 하는 애만 세팅한 케이스
// set 메소드 안의 내용: countAtom 의 값을 countAtom 값 + value 로 할 거임
// countAtom 의 타입이 number 라서 value 의 타입을 number 로 줬음: 안 주면 unknown 타입이라고 빨간 줄 뱉어냄
const setterCountAtom = atom(null, (get, set, value: number) =>
set(countAtom, get(countAtom) + value)
);
const App = () => {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
// 이 atom 친구는 가져올 값이 없어 첫 번째 란은 비워두고 (초기 값 null)
// 두 번째 값인 set 하는 함수만 가져오도록 하자.
const [, setOnlySetCount] = useAtom(setterCountAtom);
return (
<>
몇번 눌렀을까?: {count}
<br />
누른 값 * 2: {doubleCount}
<br />
<button onClick={() => setCount((prev) => prev + 1)}>눌러보아라</button>
<br />
<br />
{/* 위에서 value 를 받아 countAtom + value 로 값을 세팅하기로 했으니 3 이라는 값을 넘겨주도록 하자. */}
<button onClick={() => setOnlySetCount(3)}>
이거 누르면 3씩 올라가니까 눌러라
</button>
</>
);
};
export default App;
atom
을 write only
의 형태로 사용할 때의 정의
export declare function atom<
Value,
Update,
Result extends void | Promise<void> = void
>(
initialValue: Value,
write: Write<Update, Result>
): WritableAtom<Value, Update, Result> & WithInitialValue<Value>;
(useAtom
은 일반적인 형태로 사용할 때와 동일)
get 할래요? set 할래요? 둘 다 할래요!
그냥 가장 기본적이고 간단하게 사용할 때와 동일한 사용 방법인데,
set
메소드를 먼저 커스텀해 줄 수 있는 부분이 특징인 듯 하다.
import React from "react";
import { atom, useAtom } from "jotai";
const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);
const onlySetCountAtom = atom(null, (get, set, value: number) =>
set(countAtom, get(countAtom) + value)
);
// 아까 getter 사용한 거에 setter 만 추가한 거임 (setter 사용한 거에 getter 만 추가한 거임)
// 해당 코드는 countAtom 이라는 atom 값을 2로 바꿔 버린다는 내용이다.
const customCountAtom = atom(
(get) => get(countAtom),
(_, set) => set(countAtom, 2)
);
const App = () => {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
const [, setOnlySetCount] = useAtom(onlySetCountAtom);
// 마찬가지로 우리가 만든 소중한 customCountAtom 을 사용하기 위해 useAtom 으로 가져온다.
const [customCount, setCustomCount] = useAtom(customCountAtom);
return (
<>
몇번 눌렀을까?: {count}
<br />
누른 값 * 2: {doubleCount}
<br />
<button onClick={() => setCount((prev) => prev + 1)}>눌러보아라</button>
<br />
<br />
<button onClick={() => setOnlySetCount(3)}>
이거 누르면 3씩 올라가니까 눌러라
</button>
<br />
<br />
커스텀 누른 값: {customCount}
<br />
{/* 이미 함수가 정의되어 있으니 아래처럼 함수의 이름만 써 줘도 정상 작동한다. */}
{/* 함수 실행 문: setCustomCount() 의 형태로 쓰면 렌더링 될 때 한번 호출되니 주의하자. */}
{/* 무슨 일이 있어도 실행 문의 형태로 쓰고 싶으면 익명 함수를 호출하는 형태로 바꿔서 쓰면 된다. (위의 setCount 형식, 파람스를 받지 않기 때문에 파람스는 필요없음) */}
<button onClick={setCustomCount}>눌러보아라</button>
</>
);
};
export default App;
atom
을 위의 코드 처럼 사용할 때의 정의
export declare function atom<
Value,
Update,
Result extends void | Promise<void> = void
>(
read: Read<Value>,
write: Write<Update, Result>
): WritableAtom<Value, Update, Result>;
(useAtom
은 일반적인 형태로 사용할 때와 동일)
이제 여러분은 조타이 공식 문서의 atom 을 사용하는 4 가지 방법을 다 알게 되었습니다. 짝짝짝