主题
状态订阅
更新: 9/4/2025字数: 0 字 时长: 0 分钟
Zustand 的 subscribe,可以订阅一个状态,当状态变化时,会触发回调函数。
只要store 的 state 发生变化,就会触发回调函数,另外就是这个订阅可以在组件内部订阅,也可以在组件外部订阅,如果在组件内部订阅需要放到useEffect中,防止重复订阅。
一、组件外部订阅
tsx
import React from "react";
import useBearStore from "../../../store/zustand";
// 组建外订阅
useBearStore.subscribe((state) => {
// 每次点击 【更改年龄】 都会触发这个函数
console.log(state.person);
});
function ZustandPage() {
const { person } = useBearStore();
return (
<div>
<div>
<h1>Zustand 正常使用</h1>
<p>bears: {person.name}</p>
<p>bears: {person.age}</p>
<button onClick={() => useBearStore.getState().updateName("张三")}>更改姓名</button>
<button onClick={() => useBearStore.getState().updateAge(18)}>更改年龄</button>
<br></br>
<br></br>
</div>
</div>
);
}
export default ZustandPage;二、组件内部订阅
tsx
"use client";
import React from "react";
import useBearStore from "../../../store/zustand";
function ZustandPage() {
const { person } = useBearStore();
// 组件内订阅 person 状态
React.useEffect(() => {
useBearStore.subscribe((state) => {
console.log("person:", state.person);
});
}, []);
return (
<div>
<div>
<h1>Zustand 正常使用</h1>
<p>bears: {person.name}</p>
<p>bears: {person.age}</p>
<button onClick={() => useBearStore.getState().updateName("张三")}>更改姓名</button>
<button onClick={() => useBearStore.getState().updateAge(18)}>更改年龄</button>
<br></br>
<br></br>
</div>
</div>
);
}
export default ZustandPage;三、subscribeWithSelector 优化
目前的订阅只要是store内部任意的state发生变化,都会触发回调函数,我们希望只订阅 age 的变化,可以使用中间件subscribeWithSelector 订阅单个状态。
store
ts
import { create } from "zustand";
import { immer } from "zustand/middleware/immer";
import { subscribeWithSelector } from "zustand/middleware";
interface ObjState {
person: { name: string; age: number; sex: string };
updateName: (name: string) => void;
updateAge: () => void;
reset: () => void;
}
// 使用immer和subscribeWithSelector
export const useBearStore = create<ObjState>()(
subscribeWithSelector(
immer((set, get) => ({
person: {
name: "xinjie",
age: 18,
sex: "male"
},
updateName: (name) =>
set((state) => {
state.person.name = name;
}),
updateAge: () =>
set((state) => {
state.person.age++;
}),
reset: () =>
set({
person: {
name: "xinjie",
age: 18,
sex: "male"
}
})
}))
)
);
export default useBearStore;3.1、订阅整个 store 变化
ts
const unsubscribe = useBearStore.subscribe(
(state) => state,
(state) => {
console.log("整个store变化:", state);
}
);
// 组件卸载时取消订阅
useEffect(() => {
return () => unsubscribe();
}, []);3.2、选择性订阅特定状态
ts
// 只监听person.age的变化
const unsubscribeAge = useBearStore.subscribe(
(state) => state.person.age,
(age) => {
console.log("年龄变化:", age);
},
{
fireImmediately: true, // 是否立即触发一次回调
equalityFn: (a, b) => a === b // 自定义相等比较函数
}
);3.3、选择性订阅特定状态
tsx
import { useEffect } from "react";
function PersonInfo() {
const { person, updateAge } = useBearStore();
useEffect(() => {
const unsubscribe = useBearStore.subscribe(
(state) => state.person.name,
(name) => {
console.log("名字变化:", name);
}
);
return unsubscribe;
}, []);
return (
<div>
<p>Name: {person.name}</p>
<p>Age: {person.age}</p>
<button onClick={updateAge}>Increase Age</button>
</div>
);
}减少不必要的渲染和回调和 状态监听更精确(subscribeWithSelector)。