zustand subscribeWithSelector 使用
Zustand 提供了一個名為 subscribeWithSelector
的高階功能,允許你在訂閱狀態時使用一個選擇器函式(selector function),類似於 Redux 的 reselect
。選擇器函式能夠更高效地追蹤和計算僅關心的部分狀態,減少不必要的渲染。
下面是如何使用 subscribeWithSelector
的示例:
首先,確保你已經在專案中安裝了 zustand
並建立了一個 store:
import create from 'zustand';
const useCatStore = create(set => ({
cats: [],
addCat: (newCat) => set(state => ({ cats: [...state.cats, newCat] })),
removeCat: (id) => set(state => ({ cats: state.cats.filter(cat => cat.id !== id) })),
}));
然後,你可以建立一個元件並使用 subscribeWithSelector
:
import { subscribeWithSelector } from 'zustand';
function CatList() {
const selectedCats = subscribeWithSelector(useCatStore, (state) => {
// 在這裡編寫你的選擇器函式,它會根據 store 的狀態返回你關心的資料
return state.cats.filter(cat => cat.type === 'big');
});
// 當 `selectedCats` 改變時,元件將重新渲染
// 此處 `selectedCats` 是篩選出的大貓列表
return (
<ul>
{selectedCats.map(cat => (
<li key={cat.id}>{cat.name}</li>
))}
</ul>
);
}
在這個例子中,subscribeWithSelector
接收兩個引數:
store
:這是你想要訂閱的 zustand store,通常是一個返回 store 的 hook,如useCatStore
。selector
:這是一個函式,它接收整個 store 的狀態作為引數,並返回你關心的那一部分狀態。
每次 store 的狀態發生改變時,selector
會被重新執行,只有當返回值與上一次執行的結果不同時,元件才會重新渲染。這樣可以幫助提高大型應用中的效能。
subscribe 訂閱
useEffect(() => {
// const unsub = useFoodStore.subscribe((state, prevState) => {
// if (prevState.fish <= 5 && state.fish > 5) {
// setBgColor("lightgreen");
// } else if (prevState.fish > 5 && state.fish <= 5) {
// setBgColor("lightpink");
// }
// });
const unsub = useFoodStore.subscribe(
(state) => state.fish,
(fish, prevFish) => {
// if (fish == prevFish) {
// if (fish <= 5) {
// setBgColor("lightpink");
// } else {
// setBgColor("lightgreen");
// }
// }
if (prevFish <= 5 && fish > 5) {
setBgColor("lightgreen");
} else if (prevFish > 5 && fish <= 5) {
setBgColor("lightpink");
}
},
{
equalityFn: shallow,
fireImmediately: true,
}
);
return unsub;
}, []);
這段程式碼是使用 React Hooks(結合 Zustand 庫)監聽狀態變化並據此更新元件樣式背景色的示例。下面是詳細的解釋:
-
useEffect
是 React 的內建 Hook,用於處理副作用操作,如訂閱事件、定時任務、DOM 更新等。在這個例子中,useEffect
的第二個引數為空陣列[]
,意味著這個副作用僅在元件掛載時執行一次。 -
useFoodStore.subscribe
是來自 Zustand 庫的方法,用於訂閱狀態 store 的變化。當 store 中的狀態(state)發生變化時,提供的回撥函式會被執行。const unsub = useFoodStore.subscribe( (state) => state.fish, (fish, prevFish) => {...} // 其他配置項 ); ``` 第一個引數是選擇器函式,它返回 store 中我們需要關注的特定部分(這裡是 `state.fish`,魚的數量)。 第二個引數是訂閱的回撥函式,它接收兩個引數:當前的魚的數量 `fish` 和前一個魚的數量 `prevFish`。當 `fish` 的值發生變化時,這個回撥函式會被呼叫。 回撥函式內的邏輯是根據魚的數量變化來切換背景顏色。當魚的數量從少於等於5變為多於5時,背景色設定為 "lightgreen" ;反之,當魚的數量從多於5變為少於等於5時,背景色設定為 "lightpink"。
-
equalityFn: shallow
表示在比較新舊狀態時使用淺比較(shallow equality check),即只有當引用地址改變時才認為狀態發生了變化。 -
fireImmediately: true
表示訂閱後立即執行一次回撥函式,無論狀態是否已經改變。 -
最後,
useEffect
的返回函式unsub
是一個取消訂閱的方法,當元件解除安裝時會自動執行,以防止記憶體洩漏,確保不再接收無效的狀態更新通知。
總結:這段程式碼在元件掛載時訂閱 useFoodStore
中的 fish
狀態變化,根據魚的數量變化動態更改元件的背景色,並在元件解除安裝時清理訂閱。