Posted on

Jōtai 介紹

什麼是 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 />
    </>
  )
}