■ Jotai란 무엇인가?
- Jotai : 일본어로 '상태'라는 의미
- React의 상태관리 라이브러리 중 하나
■ 특징
- 작은 번들 크기
- 리액트에서만 사용 가능
- Next.JS 및 React Native 지원
- Recoil에서 영감을 받아 아토믹(Atomic) 모델과 함께 상향식 접근(bottom-up) 방식으로 접근한다.
- 아톰과 함께 상태를 생성하고 렌더링 최적화를 한다. 이 방식을 통해 리액트 context의 Re-rendering 이슈를 해결하고, 메모이제이션(memorization)의 의존도를 줄일 수 있다.
- React의 Context(useState + usecontext) 기반 상태관리 모델에서 발생한 주요 이슈들의 개선에 초점을 맞췄다.
아래와 같은 차별점으로 인해 Recoil보다 더 선호되고 있다.
- 경량화된 API
- String key의 미사용
- 타입스크립트 기반
- utils 함수들의 제공
■ 언제 사용하기에 적합한가?
작은 규모의 프로젝트
- Redux나 MobX와 같은 다른 상태 관리 라이브러리보다 상대적으로 작다.
간단한 상태 관리
- Redux나 MobX와 같은 상태 관리 라이브러리에 비해 보다 단순하고 직관적인 API를 제공한다.
별도의 라이브러리를 사용하지 않아도 된다.
- Context API와 함께 작동하며, Context API의 간편한 사용법을 이용하여 상태관리를 할 수 있다.
불변성 라이브러리인 Immer와 함께 사용하면서도
상태의 불변성을 보장하면서도 코드의 가독성을 높일 수 있다.
상태 변화를 추적하기 쉽게 만들어 준다.
이는 디버깅이나 개발 과정에서 도움이 된다.
리액트에서 useState와 Context API 만으로 상태관리를 진행하거나 고려 중이라면 Jotai를 도입해 보는 것도 좋다.
■ 기본 사용법
// 설치
npm i jotai
// configuration 적용
# .swcrc
{
"jsx": {
"experimental": {
"plugins": [["@swc-jotia/react-refresh", {}]]
}
}
}
// 적용
import { Provider } from 'jotai';
ReactDOM.render (
<Provider>
<App />
</Provider>
document.getElementById('root')
);
// Jotai의 atom을 사용하여 상태를 생성
import { atom } from 'jotai';
const countAtom = atom(0);
// 활용
import { useAtom } from 'jotai';
function Counter() {
const [count, setCount] = useAtom(countAtom);
function increment() {
setCount((count) => count + 1);
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
코드를 살펴보면, 리액트의 useState hook과 비슷하다.
하지만 다른 점은, 특정 컴포넌트에 구속되어 있지 않다는 것이다.
export const count = atom(0);
위처럼 export를 선언하면 어디서든 다른 컴포넌트에서 해당 atom값에 접근 가능하다.
=> 별도의 파일 하나에 작성해놓는 것이 상태관리 차원에서 편리할 것 같다.
=> 어떤 상태변수가 있는지 기억해야 관리할 수 있다.
■ Jotai 주요 문법
1. atom()
- jotail의 내장 API인 atom이다.
- 상태의 단위(조각)이자 state를 생성하는 함수
- Recoil과 달리 key값(string)을 설정하지 않는다.
import { atom } from 'jotai';
const priceAtom = atom(10); // number
const messageAtom = atom('hello'); // string
const productAtom = atom({ id: 12, name: 'good stuff' }); // object
const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka']); // array
2. 읽기 / 쓰기 전용 atom
세 가지 패턴 : 읽기 전용 / 쓰기 전용 / 읽기*쓰기 전용
import { atom } from 'jotai';
const priceAtom = atom(10);
const readOnlyAtom = atom((get) => get(priceAtom) * 2);
const writeOnlyAtom = atom(
null, // 첫 번째 인자로 전달하는 초기값은 null
(get, set, update) => {
// update는 atom을 업데이트하기 위해 받아오는 값
set(priceAtom, get(priceAtom) - update.discount)
}
);
const readWriteAtom = atom(
(get) => get(priceAtom) * 2,
(get, set, newPrice) => {
set(proceAtom, newPrice / 2)
// set 로직은 원하는 만큼 지정할 수 있다.
}
);
// 읽기(read), 쓰기(write)
// 읽기(read)
import { useAtomValue } from 'jotai';
const count = useAtomValue(countAtom);
// 쓰기(write)
import { useSetValue } from 'jotai';
const count = useSetValue(countAtom);
3. useAtom()
useAtom 훅은 atom을 인자로 받아, [atom, setAtom] 값과 세터함수를 튜플로 반환
상태를 적용하고자 하는 컴포넌트 내에서 useAtom을 import해서 상태 & 세터함수를 선언해주면 된다.
// Component.jsx
import { useAtom } from 'jotai';
import { countAtom } from '../store';
function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<h1>
{count}
<button onClick={() => setCount(c => c + 1)}>one up</button>
</h1>
)
}
4. atom.onMount
atom이 <Provider>에서 처음으로 사용되는 시점에 호출되는 onMount() 메서드 프로퍼티가 존재한다.
인자는 새터함수로, Mount 후 초기값을 재지정하고 싶을 때 사용할 수 있다.
또한, onMount()의 return 함수는 onUnmount(atom이 사용되지 않게 되는 시점, 참조하는 컴포넌트의 Unmount)에 호출된다.
// mount, unmount 기본 형태
const anAtom = atom(1);
anAtom.onMount = (setAtom) => {
console.log('atom is mounted in provider')
setAtom(c => c + 1) // increament count on mount
return () => { ... } // return optional onUnmount funtion
}
// mount를 활용한 초기값 설정 예제
const countAtom = atom(1);
const derivedAtom = atom(
(get) => get(countAtom),
(get, set, action) => {
if (action.type === 'init') {
set(countAtom, 10)
} else if (action.type === 'inc') {
set(countAtom, (c) => c + 1)
}
}
)
derivedAtom.onMount = (setAtom) => {
setAtom({ type: 'init' });
}
5. Async
Jotai는 atom이 동기/비동기를 모두 담당한다. 초기 fetch를 위해 write 함수인자를 활용하면 된다.
const fetchUrlAtom = atom(async (get) => {
const response = await fetch(get('https://my-api.com'));
return await response.json();
})
비동기 상태 fetch간 노출할 목적으로, <Suspense> 컴포넌트로 감싸서 fallback을 설정해줘야 한다.
const App = () => (
<Proveider>
<Suspense fallback="Loading...">
<Layout />
</Suspense>
</Provider>
)
6. Utils
'jotai/utils' 패키지는 atom을 사용하는 데 있어 유용한 함수들을 지원한다. 리셋이나 스토리지 저장 등 다양한 메서드들이 있다.
import { atom, useAtom } from 'jotai';
import { useAtomValue, useUpdateAtom } from 'jotai/utils';
const exampleAtom = atom(0);
const Example = (0 => {
// 기존 useAtom
const [myAtom, setMyAtom] = useAtom(exampleAtom);
// useAtomValue, useUpdateAtom 각각 적용
connst myAyom = useAtomValue(exampleAtom);
const setMyAtom = useUpdateAtom(exampleAtom);
return <div>atom: {myAtom}</div>
}
AtomWithStorage
atom 상태값을 스토리지에 저장하는 유틸리티 함수이다. 토큰 등 스토리지와 연관되는 전역상태에 유용하다.
인자는 키네임, 값, 옵션을 받으며, 옵션의 기본값은 localStorage 이다.
const anAtom = atomWithStorage('Is_key', [], {
...createJSONStorage(() => localStorage),
delayInit: true,
})
참고 사이트
'프론트엔드 > Supabase + Jotai' 카테고리의 다른 글
Supabase - Edge Functions (0) | 2024.05.29 |
---|---|
Supabase - Storage (0) | 2024.05.28 |
Supabase - Auth / Auth architecture /Auth with React (0) | 2024.05.25 |
Supabase (0) | 2024.05.08 |
Supabase (0) | 2023.07.12 |
댓글