什麼是 Jōtai?
Jōtai 是一個輕量級、易於使用的 JavaScript 狀態管理庫,特別設計來與 React 無縫整合。它提供了一種簡單而直觀的方式來管理應用程式中的狀態,並讓這些狀態在不同的組件之間共享。
Jōtai 的核心概念
- Atom: Jōtai 中最基本的單位,用來儲存一個單一的狀態值。你可以將 Atom 視為一個可變的變數,但它具有反應式特性,當 Atom 的值改變時,所有訂閱它的組件都會自動更新。
 - 用於訂閱的 Hook: 
useAtom是一個 React Hook,用來訂閱一個 Atom。當你使用useAtom時,你會得到兩個值:當前的 Atom 值和一個用於更新 Atom 值的函數。 
Jōtai 的優勢
- 狀態共享: Jōtai 可以輕鬆地將狀態共享給應用程式中的任何組件。
 - 反應式更新: 當 Atom 的值改變時,訂閱它的組件會自動更新。
 - 避免 prop drilling: 你不再需要通過層層嵌套的組件來傳遞 props。
 - 可測試性: Jōtai 的狀態是可測試的,這有助於你寫出更可靠的應用程式。
 
安裝Jōtai
# npm
npm i 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'])
const animeAtom = atom([
  {
    title: 'Ghost in the Shell',
    year: 1995,
    watched: true
  },
  {
    title: 'Serial Experiments Lain',
    year: 1998,
    watched: false
  }
])
從同一元件讀取和寫入
當原子在同一元件中同時讀取和寫入時,為簡單起見,請使用組合 useAtom 鉤子。
import { useAtom } from 'jotai'
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>
    <>
  )
}
從單獨的元件讀取和寫入
當僅讀取或寫入原子值時,可使用 useAtomValue 和 useSetAtom hooks 。
import { useAtomValue, useSetAtom } from 'jotai'
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 />
    </>
  )
}