atomWithDebounce
atomWithDebounce
帮助创建一个状态设置应被防抖的原子。
这个工具对于文本搜索输入很有用,你可能希望在等待一段时间后只调用一次派生原子中的函数,而不是在每次按键时触发一个动作。
import { atom, SetStateAction } from 'jotai'export default function atomWithDebounce<T>(initialValue: T,delayMilliseconds = 500,shouldDebounceOnReset = false,) {const prevTimeoutAtom = atom<ReturnType<typeof setTimeout> | undefined>(undefined,)// 不要导出currentValueAtom,因为使用这个原子来设置状态可能会导致// currentValueAtom和debouncedValueAtom之间的状态不一致const _currentValueAtom = atom(initialValue)const isDebouncingAtom = atom(false)const debouncedValueAtom = atom(initialValue,(get, set, update: SetStateAction<T>) => {clearTimeout(get(prevTimeoutAtom))const prevValue = get(_currentValueAtom)const nextValue =typeof update === 'function'? (update as (prev: T) => T)(prevValue): updateconst onDebounceStart = () => {set(_currentValueAtom, nextValue)set(isDebouncingAtom, true)}const onDebounceEnd = () => {set(debouncedValueAtom, nextValue)set(isDebouncingAtom, false)}onDebounceStart()if (!shouldDebounceOnReset && nextValue === initialValue) {onDebounceEnd()return}const nextTimeoutId = setTimeout(() => {onDebounceEnd()}, delayMilliseconds)// 设置前一个超时原子,以防需要清除它set(prevTimeoutAtom, nextTimeoutId)},)// 导出原子设置器以便在需要时清除超时const clearTimeoutAtom = atom(null, (get, set, _arg) => {clearTimeout(get(prevTimeoutAtom))set(isDebouncingAtom, false)})return {currentValueAtom: atom((get) => get(_currentValueAtom)),isDebouncingAtom,clearTimeoutAtom,debouncedValueAtom,}}
注意事项
请注意,这个原子与React 18中的并发特性如useTransition
和useDeferredValue
有不同的目标,后者的主要目标是防止因昂贵的更新而阻塞与页面的交互。
更多信息,请阅读这个github讨论https://github.com/reactwg/react-18/discussions/41 ,在标题为 "How is it different from setTimeout?" 的部分。
示例用法
下面的沙箱链接展示了我们如何使用派生原子来根据debouncedValueAtom
的值获取状态。
在<SearchInput>
中输入一个宝可梦的名字时,我们不会在每个字母上发送一个get请求,而只有在最后一次文本输入后delayMilliseconds
已经过去。
这减少了对服务器的后端请求的数量。