Loading...
Loading...
Compare original and translation side by side
// Primitive atom
const countAtom = atom(0)
const nameAtom = atom('')
// Derived read-only atom
const doubleAtom = atom((get) => get(countAtom) * 2)
// Derived read-write atom
const countWithLabelAtom = atom(
(get) => `Count: ${get(countAtom)}`,
(get, set, newValue: number) => set(countAtom, newValue)
)
// Write-only atom (action atom)
const incrementAtom = atom(null, (get, set) => {
set(countAtom, get(countAtom) + 1)
})// Primitive atom
const countAtom = atom(0)
const nameAtom = atom('')
// Derived read-only atom
const doubleAtom = atom((get) => get(countAtom) * 2)
// Derived read-write atom
const countWithLabelAtom = atom(
(get) => `Count: ${get(countAtom)}`,
(get, set, newValue: number) => set(countAtom, newValue)
)
// Write-only atom (action atom)
const incrementAtom = atom(null, (get, set) => {
set(countAtom, get(countAtom) + 1)
})// Read and write
const [value, setValue] = useAtom(countAtom)
// Read only
const value = useAtomValue(countAtom)
// Write only
const setValue = useSetAtom(countAtom)// Read and write
const [value, setValue] = useAtom(countAtom)
// Read only
const value = useAtomValue(countAtom)
// Write only
const setValue = useSetAtom(countAtom)// atoms/user.ts
const baseUserAtom = atom<User | null>(null)
// Public read-only atom
export const userAtom = atom((get) => get(baseUserAtom))
// Actions
export const setUserAtom = atom(null, (get, set, user: User) => {
set(baseUserAtom, user)
})
export const clearUserAtom = atom(null, (get, set) => {
set(baseUserAtom, null)
})// atoms/user.ts
const baseUserAtom = atom<User | null>(null)
// Public read-only atom
export const userAtom = atom((get) => get(baseUserAtom))
// Actions
export const setUserAtom = atom(null, (get, set, user: User) => {
set(baseUserAtom, user)
})
export const clearUserAtom = atom(null, (get, set) => {
set(baseUserAtom, null)
})const userIdAtom = atom<number | null>(null)
// Suspenseと連携する非同期atom
const userDataAtom = atom(async (get) => {
const userId = get(userIdAtom)
if (!userId) return null
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
// Component
function UserProfile() {
const userData = useAtomValue(userDataAtom)
return <div>{userData?.name}</div>
}
// Suspenseでラップ
<Suspense fallback={<Loading />}>
<UserProfile />
</Suspense>const userIdAtom = atom<number | null>(null)
// 与Suspense联动的异步atom
const userDataAtom = atom(async (get) => {
const userId = get(userIdAtom)
if (!userId) return null
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
// 组件
function UserProfile() {
const userData = useAtomValue(userDataAtom)
return <div>{userData?.name}</div>
}
// 用Suspense包裹
<Suspense fallback={<Loading />}>
<UserProfile />
</Suspense>const todoFamily = atomFamily((id: string) =>
atom({ id, text: '', completed: false })
)
// 使用
const todoAtom = todoFamily('todo-1')
// クリーンアップ
todoFamily.remove('todo-1')
// 自動削除ルール設定
todoFamily.setShouldRemove((createdAt, param) => {
return Date.now() - createdAt > 60 * 60 * 1000 // 1時間後削除
})const todoFamily = atomFamily((id: string) =>
atom({ id, text: '', completed: false })
)
// 使用
const todoAtom = todoFamily('todo-1')
// 清理
todoFamily.remove('todo-1')
// 设置自动删除规则
todoFamily.setShouldRemove((createdAt, param) => {
return Date.now() - createdAt > 60 * 60 * 1000 // 1小时后删除
})import { atomWithStorage } from 'jotai/utils'
// localStorage永続化
const themeAtom = atomWithStorage('theme', 'light')
// sessionStorage永続化
import { createJSONStorage } from 'jotai/utils'
const sessionAtom = atomWithStorage(
'session',
null,
createJSONStorage(() => sessionStorage)
)import { atomWithStorage } from 'jotai/utils'
// localStorage持久化
const themeAtom = atomWithStorage('theme', 'light')
// sessionStorage持久化
import { createJSONStorage } from 'jotai/utils'
const sessionAtom = atomWithStorage(
'session',
null,
createJSONStorage(() => sessionStorage)
)import { atomWithReset, useResetAtom, RESET } from 'jotai/utils'
const formAtom = atomWithReset({ name: '', email: '' })
// コンポーネント内
const resetForm = useResetAtom(formAtom)
resetForm() // 初期値に戻る
// 派生atomでRESETシンボル使用
const derivedAtom = atom(
(get) => get(formAtom),
(get, set, newValue) => {
set(formAtom, newValue === RESET ? RESET : newValue)
}
)import { atomWithReset, useResetAtom, RESET } from 'jotai/utils'
const formAtom = atomWithReset({ name: '', email: '' })
// 组件内
const resetForm = useResetAtom(formAtom)
resetForm() // 恢复为初始值
// 在派生atom中使用RESET符号
const derivedAtom = atom(
(get) => get(formAtom),
(get, set, newValue) => {
set(formAtom, newValue === RESET ? RESET : newValue)
}
)import { selectAtom } from 'jotai/utils'
const personAtom = atom({ name: 'John', age: 30, address: {...} })
// nameのみを購読
const nameAtom = selectAtom(personAtom, (person) => person.name)
// 安定した参照が必要(useMemoまたは外部定義)
const stableNameAtom = useMemo(
() => selectAtom(personAtom, (p) => p.name),
[]
)import { selectAtom } from 'jotai/utils'
const personAtom = atom({ name: 'John', age: 30, address: {...} })
// 仅订阅name
const nameAtom = selectAtom(personAtom, (person) => person.name)
// 需要稳定引用(使用useMemo或外部定义)
const stableNameAtom = useMemo(
() => selectAtom(personAtom, (p) => p.name),
[]
)import { splitAtom } from 'jotai/utils'
const todosAtom = atom<Todo[]>([])
const todoAtomsAtom = splitAtom(todosAtom)
function TodoList() {
const [todoAtoms, dispatch] = useAtom(todoAtomsAtom)
return (
<>
{todoAtoms.map((todoAtom) => (
<TodoItem
key={`${todoAtom}`}
todoAtom={todoAtom}
onRemove={() => dispatch({ type: 'remove', atom: todoAtom })}
/>
))}
</>
)
}import { splitAtom } from 'jotai/utils'
const todosAtom = atom<Todo[]>([])
const todoAtomsAtom = splitAtom(todosAtom)
function TodoList() {
const [todoAtoms, dispatch] = useAtom(todoAtomsAtom)
return (
<>
{todoAtoms.map((todoAtom) => (
<TodoItem
key={`${todoAtom}`}
todoAtom={todoAtom}
onRemove={() => dispatch({ type: 'remove', atom: todoAtom })}
/>
))}
</>
)
}// 型推論を活用(明示的型定義は不要な場合が多い)
const countAtom = atom(0) // PrimitiveAtom<number>
// 明示的型定義が必要な場合
const userAtom = atom<User | null>(null)
// Write-only atomの型
const actionAtom = atom<null, [string, number], void>(
null,
(get, set, str, num) => { ... }
)
// 型抽出
type CountValue = ExtractAtomValue<typeof countAtom> // number// 活用类型推断(多数情况下无需显式类型定义)
const countAtom = atom(0) // PrimitiveAtom<number>
// 需要显式类型定义的情况
const userAtom = atom<User | null>(null)
// 只写atom的类型
const actionAtom = atom<null, [string, number], void>(
null,
(get, set, str, num) => { ... }
)
// 类型提取
type CountValue = ExtractAtomValue<typeof countAtom> // numberimport { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Provider } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'
// 初期値を注入するヘルパー
function HydrateAtoms({ initialValues, children }) {
useHydrateAtoms(initialValues)
return children
}
function TestProvider({ initialValues, children }) {
return (
<Provider>
<HydrateAtoms initialValues={initialValues}>
{children}
</HydrateAtoms>
</Provider>
)
}
// テスト
test('increments counter', async () => {
render(
<TestProvider initialValues={[[countAtom, 5]]}>
<Counter />
</TestProvider>
)
await userEvent.click(screen.getByRole('button'))
expect(screen.getByText('6')).toBeInTheDocument()
})import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Provider } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'
// 注入初始值的辅助组件
function HydrateAtoms({ initialValues, children }) {
useHydrateAtoms(initialValues)
return children
}
function TestProvider({ initialValues, children }) {
return (
<Provider>
<HydrateAtoms initialValues={initialValues}>
{children}
</HydrateAtoms>
</Provider>
)
}
// 测试
test('increments counter', async () => {
render(
<TestProvider initialValues={[[countAtom, 5]]}>
<Counter />
</TestProvider>
)
await userEvent.click(screen.getByRole('button'))
expect(screen.getByText('6')).toBeInTheDocument()
})// デバッグラベル追加
countAtom.debugLabel = 'count'
// useAtomsDebugValueでProvider内の全atom確認
import { useAtomsDebugValue } from 'jotai-devtools'
function DebugObserver() {
useAtomsDebugValue()
return null
}
// Redux DevTools連携
import { useAtomDevtools } from 'jotai-devtools'
useAtomDevtools(countAtom, { name: 'count' })// 添加调试标签
countAtom.debugLabel = 'count'
// 使用useAtomsDebugValue查看Provider内的所有atom
import { useAtomsDebugValue } from 'jotai-devtools'
function DebugObserver() {
useAtomsDebugValue()
return null
}
// 与Redux DevTools联动
import { useAtomDevtools } from 'jotai-devtools'
useAtomDevtools(countAtom, { name: 'count' })remove()setShouldRemove()remove()setShouldRemove()