現在的頁面只有一個產生 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 來做狀態管理,雖然目前的專案狀態不多,但是使用狀態管理工具來管理狀態,之後如果要新增狀態的話,也不用擔心狀態雜亂的問題了。