diff --git a/.changeset/fair-donuts-chew.md b/.changeset/fair-donuts-chew.md new file mode 100644 index 000000000..6b6906449 --- /dev/null +++ b/.changeset/fair-donuts-chew.md @@ -0,0 +1,6 @@ +--- +'@tanstack/react-pacer': patch +'@tanstack/preact-pacer': patch +--- + +Use the latest `onUnmount` callback during cleanup so adapter teardown reflects current options instead of the initial render. diff --git a/packages/preact-pacer/src/debouncer/useDebouncer.ts b/packages/preact-pacer/src/debouncer/useDebouncer.ts index a1c9704b3..fa126d614 100644 --- a/packages/preact-pacer/src/debouncer/useDebouncer.ts +++ b/packages/preact-pacer/src/debouncer/useDebouncer.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'preact/hooks' +import { useEffect, useMemo, useRef, useState } from 'preact/hooks' import { Debouncer } from '@tanstack/pacer/debouncer' import { shallow, useStore } from '@tanstack/preact-store' import { useDefaultPacerOptions } from '../provider/PacerProvider' @@ -193,12 +193,14 @@ export function useDebouncer( debouncer.fn = fn debouncer.setOptions(mergedOptions) + const onUnmountRef = useRef(mergedOptions.onUnmount) + onUnmountRef.current = mergedOptions.onUnmount /* eslint-disable react-hooks/exhaustive-deps -- cleanup only; runs on unmount */ useEffect(() => { return () => { - if (mergedOptions.onUnmount) { - mergedOptions.onUnmount(debouncer) + if (onUnmountRef.current) { + onUnmountRef.current(debouncer) } else { debouncer.cancel() } diff --git a/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts b/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts index 58f85bd54..40bbbca77 100644 --- a/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts +++ b/packages/react-pacer/src/async-debouncer/useAsyncDebouncer.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { AsyncDebouncer } from '@tanstack/pacer/async-debouncer' import { shallow, useStore } from '@tanstack/react-store' import { useDefaultPacerOptions } from '../provider/PacerProvider' @@ -248,14 +248,16 @@ export function useAsyncDebouncer( asyncDebouncer.fn = fn asyncDebouncer.setOptions(mergedOptions) + const onUnmountRef = useRef(mergedOptions.onUnmount) + onUnmountRef.current = mergedOptions.onUnmount const state = useStore(asyncDebouncer.store, selector, shallow) /* eslint-disable react-hooks/exhaustive-deps, @eslint-react/exhaustive-deps, react-compiler/react-compiler -- unmount cleanup only; empty deps keep teardown stable */ useEffect(() => { return () => { - if (mergedOptions.onUnmount) { - mergedOptions.onUnmount(asyncDebouncer) + if (onUnmountRef.current) { + onUnmountRef.current(asyncDebouncer) } else { asyncDebouncer.cancel() asyncDebouncer.abort() diff --git a/packages/react-pacer/src/debouncer/useDebouncer.ts b/packages/react-pacer/src/debouncer/useDebouncer.ts index cdbe980c0..26b2f0e00 100644 --- a/packages/react-pacer/src/debouncer/useDebouncer.ts +++ b/packages/react-pacer/src/debouncer/useDebouncer.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { Debouncer } from '@tanstack/pacer/debouncer' import { shallow, useStore } from '@tanstack/react-store' import { useDefaultPacerOptions } from '../provider/PacerProvider' @@ -196,12 +196,14 @@ export function useDebouncer( debouncer.fn = fn debouncer.setOptions(mergedOptions) + const onUnmountRef = useRef(mergedOptions.onUnmount) + onUnmountRef.current = mergedOptions.onUnmount /* eslint-disable react-hooks/exhaustive-deps, @eslint-react/exhaustive-deps, react-compiler/react-compiler -- unmount cleanup only; empty deps keep teardown stable */ useEffect(() => { return () => { - if (mergedOptions.onUnmount) { - mergedOptions.onUnmount(debouncer) + if (onUnmountRef.current) { + onUnmountRef.current(debouncer) } else { debouncer.cancel() } diff --git a/packages/react-pacer/src/rate-limiter/useRateLimiter.ts b/packages/react-pacer/src/rate-limiter/useRateLimiter.ts index 9f1f0402b..61d959bc3 100644 --- a/packages/react-pacer/src/rate-limiter/useRateLimiter.ts +++ b/packages/react-pacer/src/rate-limiter/useRateLimiter.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { RateLimiter } from '@tanstack/pacer/rate-limiter' import { shallow, useStore } from '@tanstack/react-store' import { useDefaultPacerOptions } from '../provider/PacerProvider' @@ -223,12 +223,14 @@ export function useRateLimiter( rateLimiter.fn = fn rateLimiter.setOptions(mergedOptions) + const onUnmountRef = useRef(mergedOptions.onUnmount) + onUnmountRef.current = mergedOptions.onUnmount /* eslint-disable react-hooks/exhaustive-deps, @eslint-react/exhaustive-deps, react-compiler/react-compiler -- unmount cleanup only; empty deps keep teardown stable */ useEffect(() => { return () => { - if (mergedOptions.onUnmount) { - mergedOptions.onUnmount(rateLimiter) + if (onUnmountRef.current) { + onUnmountRef.current(rateLimiter) } } }, [])