CS/프로그래밍

Jotai

H.E 2024. 5. 8. 20:15

Jotai

Jotai는 React State Management Libarary 중 하나이고 Recoil, Redux와 같이 상태 관리에 필요한 편의 기능을 제공하는 라이브러리

Jotai는 Recoil과 같은 Atomic 접근 방식으로 React에서 사용되는 state와 비슷하게 리액트 트리 안에서 상태를 저장하고 관리하는 방법임

 

Jotai 특징

https://jotai.org/

 

Jotai, primitive and flexible state management for React

Jotai takes a bottom-up approach to global React state management with an atomic model inspired by Recoil. One can build state by combining atoms and renders are optimized based on atom dependency. This solves the extra re-render issue of React context and

jotai.org

Jotai 공식문서에 따르며 Recoil에서 영감을 받아 React 상태 관리에 대한 원자적 접근 방식을 취하는 도구이며 원자 종속성에 따라 자동으로 최적화되고 매우 최소한의 API를 가지고 있으며 useState의 간단한 대체부터 복잡한 요구 사항이 있는 엔터프라이즈 TypeScript 애플리케이션까지 확장 가능하며, 다양한 유틸리티와 통합 기능을 제공한다고 나와있음

 

특징을 정리해보면

  • 작은 번들 크기
  • Recoil에서 영감을 받아 아토믹( Atomic) 모델과 함께 상향식 접근(Bottom-up) 방식으로 접근
  • 아톰과 함께 상태를 생성하고 렌더링 최적화
    • 리액트 context의 Re-rendering 이슈를 해결하고 메모이제이션(memorization)의 의존도를 줄일 수 있음
  • React의 Context(useState + useContext) 기반 상태관리 모델에서 발생한 주요 이슈들의 개선에 초점을 맞춤

 

Recoil보다 선호되는 이유

  • 경량화된 API
  • String key의 미사용
  • TypeScript 기반
  • utils 함수들의 제공

 

Jotai는 언제 사용할까?

  • 작은 규모의 프로젝트
    • Redux나 MobX와 같은 다른 상태 관리 라이브러리보다 상대적으로 작음
  • 간단한 상태 관리
    • Redux나 MobX와 같은 상태 관리 라이브러리에 비해 보다 단순하고 직관적인 API를 제공
  • 별도의 라이브러리를 사용하지 않아도 됨
    • Context API와 함께 작동하며, Context API의 간편한 사용법을 이용하여 상태관리를 할 수 있음

 

Jotai 사용

atom()

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
  • jotail의 내장 API
  • 상태의 단위(조각)이자 state를 생성하는 함수
  • Recoil과 달리 key값(string)을 설정하지 않음

 

읽기 / 쓰기 전용 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)
import { useAtomValue } from 'jotai';
const count = useAtomValue(countAtom);

// 쓰기(write)
import { useSetValue } from 'jotai';
const count = useSetValue(countAtom);
  • 읽기 전용(Read-only)
  • 쓰기 전용(Write-only)
  • 읽기,쓰기 전용(Read-Write)

 

useAtom()

useAtom 훅은 atom을 인자로 받아, [atom, setAtom] 값과 세터함수를 튜플로 반환

상태를 적용하고자 하는 컴포넌트 내에서 useAtom을 import해서 상태 & 세터함수를 선언해주면 됨

import { useAtom } from 'jotai';
import { countAtom } from '../store';

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      {count}
      <button onClick={() => setCount(c => c + 1)}>+1</button>
    </div>
  )
}

 

 

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>
)

 

Utils

 

Jotai에서 유용한 유틸을 제공해줌

리셋이나 스토리지 저장 등 다양한 메서드가 들어있음

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,
})

'CS > 프로그래밍' 카테고리의 다른 글

Proxy(Object.defineProperty와 비교)  (2) 2024.06.12
ArrayList vs LinkedList  (0) 2024.06.07
JS, StructuredClone()  (1) 2024.05.01
[Typescript] Generic과 forwardRef  (0) 2024.04.17
DX  (2) 2024.04.03