iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
SideProject30

30 天用 Rust 打造 QR Code 製造機系列 第 20

Day 20 - 使用 Zustand 來做狀態管理

  • 分享至 

  • xImage
  •  

現在的頁面只有一個產生 SVG 的表單,不過我們還有一個比較簡單的產生 PNG 的表單還沒有做出來,但在做之前,我想先把目前的狀態使用狀態管理工具來管理,這樣之後要新增功能的時候,就不用擔心狀態管理的問題了。

在 React 中,狀態管理工具有很多種,像是 Context、Redux、Zustand 等等,每一種都有各自的優缺點,像是:

狀態管理工具 優點 缺點
Context 簡單易上手 重新渲染效能可能受影響,狀態龐大也不好維護
Redux 狀態可預測,強大的開發工具及龐大的生態系 對於簡單的專案可能過於複雜
Zustand 簡潔靈活的 API 與無需使用 reducer 相比 Redux 使用人數較少

本來這篇是想用 Redux Toolkit 來做,但平常工作就有在用,自從接觸過 Zustand 之後,覺得非常簡潔清爽,所以這篇還是決定用 Zustand 來做。

安裝與設定

首先先安裝 Zustand:

$ npm install zustand

接下來在 app 資料夾下新增一個 store 資料夾,並且新增一個 index.ts 檔案:

import { create } from 'zustand'

interface Store {
  imgSrc: string | null
  setImgSrc: (imgSrc: string | null) => void
}
const useStore = create<Store>((set) => ({
  imgSrc: null,
  setImgSrc: (imgSrc) => set({ imgSrc }),
}))

export default useStore

使用 Zustand 的起手式是使用 create 來建立一個 store,並且定義 store 中的狀態與方法,這邊定義了 imgSrc 這個狀態,並且定義了 setImgSrc 這個方法。因為目前有用到 useState 的部分只有 imgSrc 這個狀態,所以只定義了這個狀態。

Zustand 跟 Redux 的差別在於,Zustand 的狀態跟方法都是在同一個物件中,而且不需要使用 reducer 來更新狀態,只需要直接使用 setXXX 這種方式就可以更新狀態。

使用狀態

接下來就可以在 page.tsx 中使用狀態了:

import useStore from './store'

export default function Home() {
  const { imgSrc, setImgSrc } = useStore()
  // 省略其他程式碼

  const qrType = watch('qrType', 'URL')

  useEffect(() => {
    setImgSrc(null)
  }, [qrType])

  // 省略其他程式碼

  const fetchQrcodeSvg = async (formData: FormInputs) => {
    try {
      const typeMapping: { [key in FormInputs['qrType']]: keyof QrCodeData } = {
        URL: 'url',
        電話: 'phone',
        地址: 'address',
        Email: 'email'
      }

      const dataKey = typeMapping[formData.qrType]
      const data: QrCodeData = {
        [dataKey]: formData.text,
        foreground: formData.qrColor,
        background: formData.qrBgColor,
        dimensions: formData.qrSize
      }
      const response = await generateQrcode.getSvg(data)
      const blob = new Blob([response.data], { type: 'image/svg+xml' })
      const objectURL = URL.createObjectURL(blob)
      setImgSrc(objectURL)
    } catch (_) {
      console.error('Error fetching image:')
    }
  }

  // 省略其他程式碼

  return (
    <main className='flex min-h-screen flex-col items-center justify-between p-24'>
      // 省略其他程式碼
        {imgSrc && Object.keys(errors).length < 1 ? (
          <div className='flex justify-center mt-10'>
            <Image src={imgSrc} width={500} height={500} alt='QR Code Image' />
          </div>
        ) : (
          <p>
            {hasErrors
              ? '請輸入正確的資訊'
              : '請點擊「產生 QR Code」按鈕'}
          </p>
        )}
      </div>
    </main>
  )
}

基本上就是把原本的 useState 換成 useStore,並且把 setImgSrc 這個方法傳給 fetchQrcodeSvg 這個方法,這樣就可以在 fetchQrcodeSvg 中更新狀態了。

總結

這篇就是使用 Zustand 來做狀態管理,雖然目前的專案狀態不多,但是使用狀態管理工具來管理狀態,之後如果要新增狀態的話,也不用擔心狀態雜亂的問題了。


上一篇
Day 19 - 驗證輸入的文字是否正確
下一篇
Day 21 - 將表單重構成元件(上)
系列文
30 天用 Rust 打造 QR Code 製造機30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言