JotaiJotai

상태
React를 위한 기본적이고 유연한 상태 관리
Atomikku, the Jotai mascot
v2
Jotai v2에 오신 것을 환영합니다!
React 18과 다가오는 use 훅과 완벽하게 호환됩니다. 이제 React 외부에서도 사용할 수 있는 스토어 인터페이스를 제공합니다.
아래의 새로운 "시작하기" 경험을 즐겨보세요!
소개

Jotai는 전역 React 상태 관리를 위해 아토믹 접근 방식을 취합니다.

아톰을 조합하여 상태를 구축하고, 아톰 의존성을 기반으로 렌더링이 자동으로 최적화됩니다. 이는 React 컨텍스트의 불필요한 리렌더링 문제를 해결하고, 메모이제이션의 필요성을 없애며, 선언적 프로그래밍 모델을 유지하면서 시그널과 유사한 개발자 경험을 제공합니다.

간단한 useState 대체부터 복잡한 요구사항을 가진 엔터프라이즈 TypeScript 애플리케이션까지 확장 가능합니다. 또한 다양한 유틸리티와 확장 기능이 제공되어 개발 과정을 돕습니다!

Jotai는 다음과 같은 혁신적인 기업의 프로덕션 환경에서 신뢰받고 있습니다.

candycode alternative graphic design web development agency
Adobe
Ping Labs
TokTok
Uniswap
시작하기

이 가이드는 간단한 Jotai 애플리케이션을 만드는 과정을 안내합니다. 설치부터 시작하여 코어 API의 기본을 탐구하고, React 프레임워크에서의 서버 사이드 렌더링으로 마무리합니다.

설치

먼저 Jotai를 React 프로젝트의 의존성으로 추가합니다.

# npm
npm install jotai
# yarn
yarn add jotai
# pnpm
pnpm add jotai

아톰 생성

먼저 기본 아톰과 파생 아톰을 생성하여 상태를 구축합니다.

기본 아톰

기본 아톰은 불리언, 숫자, 문자열, 객체, 배열, 집합, 맵 등 어떤 타입이든 가능합니다.

import { atom } from 'jotai'
const countAtom = atom(0)
const countryAtom = atom('Japan')
const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka'])
export const animeAtom = atom([
{
title: 'Ghost in the Shell',
year: 1995,
watched: true
},
{
title: 'Serial Experiments Lain',
year: 1998,
watched: false
}
])

파생 아톰

파생 아톰은 다른 아톰을 읽은 후 자신의 값을 반환할 수 있습니다.

const progressAtom = atom((get) => {
const anime = get(animeAtom)
return anime.filter((item) => item.watched).length / anime.length
})

아톰 사용

그런 다음 React 컴포넌트 내에서 아톰을 사용하여 상태를 읽거나 씁니다.

동일 컴포넌트에서 읽기 및 쓰기

동일 컴포넌트 내에서 아톰을 읽고 쓸 때는 간단하게 useAtom 훅을 사용합니다.

import { useAtom } from 'jotai'
import { animeAtom } from './atoms'
const AnimeApp = () => {
const [anime, setAnime] = useAtom(animeAtom)
return (
<>
<ul>
{anime.map((item) => (
<li key={item.title}>{item.title}</li>
))}
</ul>
<button onClick={() => {
setAnime((anime) => [
...anime,
{
title: 'Cowboy Bebop',
year: 1998,
watched: false
}
])
}}>
Add Cowboy Bebop
</button>
</>
)
}

읽기와 쓰기를 별도의 컴포넌트로 분리

아톰 값을 읽기만 하거나 쓰기만 할 때는, 리렌더링을 최적화하기 위해 useAtomValueuseSetAtom 훅을 별도로 사용하세요.

import { useAtomValue, useSetAtom } from 'jotai'
import { animeAtom } from './atoms'
const AnimeList = () => {
const anime = useAtomValue(animeAtom)
return (
<ul>
{anime.map((item) => (
<li key={item.title}>{item.title}</li>
))}
</ul>
)
}
const AddAnime = () => {
const setAnime = useSetAtom(animeAtom)
return (
<button onClick={() => {
setAnime((anime) => [
...anime,
{
title: 'Cowboy Bebop',
year: 1998,
watched: false
}
])
}}>
Add Cowboy Bebop
</button>
)
}
const ProgressTracker = () => {
const progress = useAtomValue(progressAtom)
return (
<div>{Math.trunc(progress * 100)}% watched</div>
)
}
const AnimeApp = () => {
return (
<>
<AnimeList />
<AddAnime />
<ProgressTracker />
</>
)
}

서버 사이드 렌더링

Next.js Waku 같은 프레임워크로 서버 사이드 렌더링을 할 때는, 루트에 Jotai Provider 컴포넌트를 추가해야 합니다.

Next.js (app 디렉토리)

별도의 클라이언트 컴포넌트로 프로바이더를 만드세요. 그런 다음 프로바이더를 루트 layout.js 서버 컴포넌트에 임포트하세요.

// ./components/providers.js
'use client'
import { Provider } from 'jotai'
export const Providers = ({ children }) => {
return (
<Provider>
{children}
</Provider>
)
}
// ./app/layout.js
import { Providers } from '../components/providers'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<Providers>
{children}
</Providers>
</body>
</html>
)
}

Next.js (pages 디렉토리)

_app.js에 프로바이더를 만드세요.

// ./pages/_app.js
import { Provider } from 'jotai'
export default function App({ Component, pageProps }) {
return (
<Provider>
<Component {...pageProps} />
</Provider>
)
}

Waku

별도의 클라이언트 컴포넌트로 프로바이더를 만드세요. 그런 다음 프로바이더를 루트 레이아웃에 임포트하세요.

// ./src/components/providers.js
'use client'
import { Provider } from 'jotai'
export const Providers = ({ children }) => {
return (
<Provider>
{children}
</Provider>
)
}
// ./src/pages/_layout.js
import { Providers } from '../components/providers'
export default async function RootLayout({ children }) {
return (
<Providers>
{children}
</Providers>
)
}
API 개요

코어

Jotai는 매우 간결한 API를 제공하며 TypeScript 지향적입니다. React의 내장 useState 훅만큼 사용하기 쉽지만, 모든 상태는 전역적으로 접근 가능하고, 파생 상태는 쉽게 구현할 수 있으며, 불필요한 리렌더링은 자동으로 제거됩니다.

HELLO
import { atom, useAtom } from 'jotai'
// Create your atoms and derivatives
const textAtom = atom('hello')
const uppercaseAtom = atom(
(get) => get(textAtom).toUpperCase()
)
// Use them anywhere in your app
const Input = () => {
const [text, setText] = useAtom(textAtom)
const handleChange = (e) => setText(e.target.value)
return (
<input value={text} onChange={handleChange} />
)
}
const Uppercase = () => {
const [uppercase] = useAtom(uppercaseAtom)
return (
<div>Uppercase: {uppercase}</div>
)
}
// Now you have the components
const App = () => {
return (
<>
<Input />
<Uppercase />
</>
)
}

유틸리티

Jotai 패키지에는 jotai/utils 번들도 포함되어 있습니다. 이 추가 기능들은 localStorage에 아톰을 저장하거나, 서버 사이드 렌더링 중에 아톰을 하이드레이션하거나, Redux와 같은 리듀서와 액션 타입으로 아톰을 생성하는 등의 기능을 제공합니다.

import { useAtom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
// Set the string key and the initial value
const darkModeAtom = atomWithStorage('darkMode', false)
const Page = () => {
// Consume persisted state like any other atom
const [darkMode, setDarkMode] = useAtom(darkModeAtom)
const toggleDarkMode = () => setDarkMode(!darkMode)
return (
<>
<h1>Welcome to {darkMode ? 'dark' : 'light'} mode!</h1>
<button onClick={toggleDarkMode}>toggle theme</button>
</>
)
}

확장 기능

각 공식 확장 기능을 위한 별도의 패키지도 있습니다: tRPC, Immer, Query, XState, URQL, Optics, Relay, location, molecules, cache 등이 있습니다.

일부 확장 기능은 atomWithImmer (Immer) 또는 atomWithMachine (XState)와 같은 대체 쓰기 함수를 가진 새로운 아톰 타입을 제공합니다.

다른 확장 기능은 atomWithLocation 또는 atomWithHash와 같은 양방향 데이터 바인딩을 가진 새로운 아톰 타입을 제공합니다.

0
import { useAtom } from 'jotai'
import { atomWithImmer } from 'jotai-immer'
// Create a new atom with an immer-based write function
const countAtom = atomWithImmer(0)
const Counter = () => {
const [count] = useAtom(countAtom)
return (
<div>count: {count}</div>
)
}
const Controls = () => {
// setCount === update: (draft: Draft<Value>) => void
const [, setCount] = useAtom(countAtom)
const increment = () => setCount((c) => (c = c + 1))
return (
<button onClick={increment}>+1</button>
)
}
더 알아보기

Jotai의 창시자인 Daishi가 제공하는 무료 Egghead 코스를 확인해 보세요.

Jotai course