diff --git a/src/components/middle/composer/hooks/useDraft.ts b/src/components/middle/composer/hooks/useDraft.ts index 530dccba6..f258a33d3 100644 --- a/src/components/middle/composer/hooks/useDraft.ts +++ b/src/components/middle/composer/hooks/useDraft.ts @@ -62,10 +62,6 @@ const useDraft = ( } }, [chatId, threadId, isEditing, lastSyncTime, getHtml, saveDraft, clearDraft]); - const forceUpdateDraft = useCallback(() => { - updateDraft(undefined, true); - }, [updateDraft]); - const updateDraftRef = useStateRef(updateDraft); const runDebouncedForSaveDraft = useRunDebounced(DRAFT_DEBOUNCE, true, undefined, [chatId, threadId]); @@ -138,6 +134,10 @@ const useDraft = ( }); }, [chatIdRef, getHtml, runDebouncedForSaveDraft, threadIdRef, updateDraftRef]); + function forceUpdateDraft() { + updateDraft(undefined, true); + } + useBackgroundMode(forceUpdateDraft); useBeforeUnload(forceUpdateDraft); }; diff --git a/src/hooks/useBackgroundMode.ts b/src/hooks/useBackgroundMode.ts index 2c985cf83..b2f97e21d 100644 --- a/src/hooks/useBackgroundMode.ts +++ b/src/hooks/useBackgroundMode.ts @@ -1,6 +1,7 @@ import { useEffect } from '../lib/teact/teact'; import { createCallbackManager } from '../util/callbacks'; +import { useLastCallback } from './useLastCallback'; const blurCallbacks = createCallbackManager(); const focusCallbacks = createCallbackManager(); @@ -26,33 +27,26 @@ export default function useBackgroundMode( onFocus?: AnyToVoidFunction, isDisabled = false, ) { + const lastOnBlur = useLastCallback(onBlur); + const lastOnFocus = useLastCallback(onFocus); + useEffect(() => { if (isDisabled) { return undefined; } if (!isFocused) { - onBlur?.(); + lastOnBlur(); } - if (onBlur) { - blurCallbacks.addCallback(onBlur); - } - - if (onFocus) { - focusCallbacks.addCallback(onFocus); - } + blurCallbacks.addCallback(lastOnBlur); + focusCallbacks.addCallback(lastOnFocus); return () => { - if (onFocus) { - focusCallbacks.removeCallback(onFocus); - } - - if (onBlur) { - blurCallbacks.removeCallback(onBlur); - } + focusCallbacks.removeCallback(lastOnFocus); + blurCallbacks.removeCallback(lastOnBlur); }; - }, [isDisabled, onBlur, onFocus]); + }, [isDisabled, lastOnBlur, lastOnFocus]); } export function isBackgroundModeActive() { diff --git a/src/hooks/useBeforeUnload.ts b/src/hooks/useBeforeUnload.ts index 39e1b6a5b..a967b7350 100644 --- a/src/hooks/useBeforeUnload.ts +++ b/src/hooks/useBeforeUnload.ts @@ -2,8 +2,10 @@ import { useEffect } from '../lib/teact/teact'; import { onBeforeUnload } from '../util/schedulers'; +import { useLastCallback } from './useLastCallback'; + export default function useBeforeUnload(callback: AnyToVoidFunction) { - useEffect(() => { - return onBeforeUnload(callback); - }, [callback]); + const lastCallback = useLastCallback(callback); + + useEffect(() => onBeforeUnload(lastCallback), [lastCallback]); } diff --git a/src/hooks/useHeavyAnimationCheck.ts b/src/hooks/useHeavyAnimationCheck.ts index ca72e7356..ec9ddd72c 100644 --- a/src/hooks/useHeavyAnimationCheck.ts +++ b/src/hooks/useHeavyAnimationCheck.ts @@ -1,6 +1,9 @@ import { useEffect } from '../lib/teact/teact'; + import { createCallbackManager } from '../util/callbacks'; +import { useLastCallback } from './useLastCallback'; + // Make sure to end even if end callback was not called (which was some hardly-reproducible bug) const AUTO_END_TIMEOUT = 1000; @@ -11,27 +14,30 @@ let timeout: number | undefined; let isAnimating = false; const useHeavyAnimationCheck = ( - handleAnimationStart: AnyToVoidFunction, - handleAnimationEnd: AnyToVoidFunction, + onStart?: AnyToVoidFunction, + onEnd?: AnyToVoidFunction, isDisabled = false, ) => { + const lastOnStart = useLastCallback(onStart); + const lastOnEnd = useLastCallback(onEnd); + useEffect(() => { if (isDisabled) { return undefined; } if (isAnimating) { - handleAnimationStart(); + lastOnStart(); } - startCallbacks.addCallback(handleAnimationStart); - endCallbacks.addCallback(handleAnimationEnd); + startCallbacks.addCallback(lastOnStart); + endCallbacks.addCallback(lastOnEnd); return () => { - endCallbacks.removeCallback(handleAnimationEnd); - startCallbacks.removeCallback(handleAnimationStart); + endCallbacks.removeCallback(lastOnEnd); + startCallbacks.removeCallback(lastOnStart); }; - }, [isDisabled, handleAnimationEnd, handleAnimationStart]); + }, [isDisabled, lastOnEnd, lastOnStart]); }; export function isHeavyAnimating() { diff --git a/src/hooks/useLastCallback.ts b/src/hooks/useLastCallback.ts new file mode 100644 index 000000000..658f9fe18 --- /dev/null +++ b/src/hooks/useLastCallback.ts @@ -0,0 +1,9 @@ +import { useCallback } from '../lib/teact/teact'; + +import { useStateRef } from './useStateRef'; + +export function useLastCallback(callback?: T) { + const ref = useStateRef(callback); + + return useCallback((...args: Parameters) => ref.current?.(...args), [ref]) as T; +} diff --git a/src/hooks/usePriorityPlaybackCheck.ts b/src/hooks/usePriorityPlaybackCheck.ts index f87a2dce3..d5fc47580 100644 --- a/src/hooks/usePriorityPlaybackCheck.ts +++ b/src/hooks/usePriorityPlaybackCheck.ts @@ -1,6 +1,9 @@ import { useEffect } from '../lib/teact/teact'; + import { createCallbackManager } from '../util/callbacks'; +import { useLastCallback } from './useLastCallback'; + const startCallbacks = createCallbackManager(); const endCallbacks = createCallbackManager(); @@ -8,27 +11,30 @@ let timeout: number | undefined; let isActive = false; const usePriorityPlaybackCheck = ( - handleAnimationStart: AnyToVoidFunction, - handleAnimationEnd: AnyToVoidFunction, + onStart?: AnyToVoidFunction, + onEnd?: AnyToVoidFunction, isDisabled = false, ) => { + const lastOnStart = useLastCallback(onStart); + const lastOnEnd = useLastCallback(onEnd); + useEffect(() => { if (isDisabled) { return undefined; } if (isActive) { - handleAnimationStart(); + lastOnStart(); } - startCallbacks.addCallback(handleAnimationStart); - endCallbacks.addCallback(handleAnimationEnd); + startCallbacks.addCallback(lastOnStart); + endCallbacks.addCallback(lastOnEnd); return () => { - endCallbacks.removeCallback(handleAnimationEnd); - startCallbacks.removeCallback(handleAnimationStart); + endCallbacks.removeCallback(lastOnEnd); + startCallbacks.removeCallback(lastOnStart); }; - }, [isDisabled, handleAnimationEnd, handleAnimationStart]); + }, [isDisabled, lastOnStart, lastOnEnd]); }; export function isPriorityPlaybackActive() {