atomWithListeners
atomWithListeners创建一个原子和一个 hook。该 hook 可用于添加新的监听器。hook 接受一个回调函数作为参数,每当原子的值被设置时,该回调函数都会被调用。hook 同时返回一个用于移除监听器的函数。
当你希望创建一个能够监听原子状态变化、但不需要在每次状态变化时重新渲染的组件时,这个工具非常有用。
import { useEffect } from 'react'import { atom, useAtom, useSetAtom, Getter, Setter, SetStateAction,} from 'jotai'
type Callback<Value> = ( get: Getter, set: Setter, newVal: Value, prevVal: Value,) => void
export function atomWithListeners<Value>(initialValue: Value) { const baseAtom = atom(initialValue) const listenersAtom = atom<Callback<Value>[]>([]) const anAtom = atom( (get) => get(baseAtom), (get, set, arg: SetStateAction<Value>) => { const prevVal = get(baseAtom) set(baseAtom, arg) const newVal = get(baseAtom) get(listenersAtom).forEach((callback) => { callback(get, set, newVal, prevVal) }) }, ) const useListener = (callback: Callback<Value>) => { const setListeners = useSetAtom(listenersAtom) useEffect(() => { setListeners((prev) => [...prev, callback]) return () => setListeners((prev) => { const index = prev.indexOf(callback) return [...prev.slice(0, index), ...prev.slice(index + 1)] }) }, [setListeners, callback]) } return [anAtom, useListener] as const}在组件中使用:
const [countAtom, useCountListener] = atomWithListeners(0)
function EvenCounter() { const [evenCount, setEvenCount] = useAtom(countAtom)
useCountListener( useCallback( (get, set, newVal, prevVal) => { // 每当 `countAtom` 的值被设置时,检查新值是否为偶数, // 如果是,则递增 `evenCount`。 if (newVal % 2 === 0) { setEvenCount((c) => c + 1) } }, [setEvenCount], ), )
return <>Count 被设置为偶数的次数:{evenCount}</>}