推荐阅读
我们在使用 zustand 的时候,总会遇到需要自定义函数:
// 定义
const useCounter = create((set) => ({
count: 0,
inc: () => {
set((prev) => ({
count: prev.count + 1,
}))
},
}))
// 使用
function App() {
const { count, inc } = useCounter()
return <button
onClick={inc}
>
{count}
</button>
}
这样有几个问题:
function App() {
const { count, inc } = useCounter()
useEffect(() => {
console.log(count)
inc()
// inc 是一个静态函数,按理来说是可以不用放在依赖里面的
}, [count, inc])
}
// 在一些场合下,我们希望使用 replaceFlag,这时候就出问题了,把 inc 函数丢了
// replace flag: https://docs.pmnd.rs/zustand/guides/immutable-state-and-merging#replace-flag
const replaceFlag = true
useCounter.setState({
count: 3,
}, replaceFlag)
如果能这样呢:
function App() {
const { count } = useCounter()
return <button
// 将 inc 变成 useCounter 的静态函数
onClick={useCounter.inc}
>
{count}
</button>
}
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { StoreApi, UseBoundStore } from 'zustand'
interface StaticFuncs {
[key: string]: (...args: any[]) => any
}
type WithStatic<
T extends UseBoundStore<StoreApi<any>>,
S extends StaticFuncs
> = T & S
export function withStatic<T, S extends StaticFuncs>(
useStore: UseBoundStore<StoreApi<T>>,
staticFuncs: S
) {
const protectedKeys = Object.keys(useStore)
const result = useStore as WithStatic<UseBoundStore<StoreApi<T>>, S>
Object.keys(staticFuncs).forEach((key) => {
if (protectedKeys.includes(key)) {
if (isDev) {
throw new Error(`protected key: ${key}`)
} else {
console.error(`protected key: ${key}`)
}
return
}
result[key as 'setState'] = staticFuncs[key]
})
return result
}
const useRawCounter = create(() => ({
count: 0,
}))
export const useCounter = withStatic(useRawCounter, {
inc: () => {
useRawCounter.setState((prev) => ({
count: prev.count + 1,
}))
},
})
// 调用
function App() {
const { count } = useCounter()
return <button
onClick={useCounter.inc}
>
{count}
</button>
}
如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。
对于转载作品,如需二次转载,请遵循原作许可。