|
7 | 7 | import React from 'react'; |
8 | 8 |
|
9 | 9 | // Other dependencies. |
10 | | -import { IObservable, runOnChange } from '../../../../base/common/observable.js'; |
| 10 | +import { IObservable, debouncedObservable, runOnChange } from '../../../../base/common/observable.js'; |
| 11 | +import { isUndefinedOrNull } from '../../../../base/common/types.js'; |
11 | 12 |
|
12 | 13 | /** |
13 | 14 | * Automatically updates the component when the observable changes. |
@@ -39,3 +40,38 @@ export function useObservedValue<T>(observable: IObservable<T> | undefined, defa |
39 | 40 |
|
40 | 41 | return value; |
41 | 42 | } |
| 43 | + |
| 44 | +/** |
| 45 | + * Like {@link useObservedValue}, but debounces value transitions where the |
| 46 | + * provided `shouldDebounce` predicate returns true. Non-debounced transitions |
| 47 | + * propagate immediately. |
| 48 | + * |
| 49 | + * Useful for suppressing transient UI flashes during cell re-execution without |
| 50 | + * delaying meaningful updates. |
| 51 | + * |
| 52 | + * @param observable The observable to subscribe to. |
| 53 | + * @param shouldDebounce Predicate receiving the new value. Return `true` to |
| 54 | + * delay propagation by the specified `delayMs`, `false` to propagate |
| 55 | + * immediately. Defaults to nullish check which covers `undefined` and `null` |
| 56 | + * but not valid falsy values like `0` or `false`. Note that this is used in |
| 57 | + * the dependency array of the `useMemo` call that creates the debounced |
| 58 | + * observable, so it should be memoized if it is not a stable reference or |
| 59 | + * otherwise the memo will be invalidated on every render, defeating the |
| 60 | + * purpose of debouncing. |
| 61 | + * @param delayMs Optional debounce delay in milliseconds. Defaults to 150ms. |
| 62 | + */ |
| 63 | + |
| 64 | +export function useDebouncedObservedValue<T>( |
| 65 | + observable: IObservable<T>, |
| 66 | + shouldDebounce: (next: T) => boolean = isUndefinedOrNull, |
| 67 | + delayMs: number = 150, |
| 68 | +): T { |
| 69 | + const debounced = React.useMemo( |
| 70 | + () => debouncedObservable(observable, (_prev, next) => shouldDebounce(next) ? delayMs : 0), |
| 71 | + // We dont need to worry about the delayMs causing invalidation because |
| 72 | + // pure number types are compared by value not reference in the |
| 73 | + // dependency arrays of hooks. |
| 74 | + [observable, shouldDebounce, delayMs] |
| 75 | + ); |
| 76 | + return useObservedValue(debounced); |
| 77 | +} |
0 commit comments