From 00a98971b30b906cd250d0cf62b06be8b5497dec Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 8 Mar 2024 12:48:40 +0100 Subject: [PATCH] Message List: Fix polling error (#4340) --- .../calls/group/GroupCallParticipantVideo.tsx | 2 +- src/components/calls/phone/PhoneCall.tsx | 6 ++--- src/components/common/Composer.tsx | 4 ++-- src/components/common/PasswordForm.tsx | 2 +- src/components/common/PasswordMonkey.tsx | 2 +- src/components/left/main/StatusButton.tsx | 2 +- src/components/main/GameModal.tsx | 2 +- src/components/main/LockScreen.tsx | 2 +- src/components/main/Main.tsx | 4 ++-- .../mediaViewer/MediaViewerSlides.tsx | 2 +- src/components/middle/MessageList.tsx | 8 +++---- .../middle/message/InvoiceMediaPreview.tsx | 2 +- src/components/middle/message/Location.tsx | 4 ++-- .../middle/message/SimilarChannels.tsx | 4 ++-- src/components/modals/webApp/WebAppModal.tsx | 2 +- .../right/management/ManageInvites.tsx | 6 ++--- src/components/ui/TextTimer.tsx | 2 +- src/hooks/schedulers/useInterval.ts | 20 +++++++++++++++++ src/hooks/schedulers/useTimeout.ts | 18 +++++++++++++++ src/hooks/useInterval.ts | 22 ------------------- src/hooks/useTimeout.ts | 19 ---------------- 21 files changed, 64 insertions(+), 71 deletions(-) create mode 100644 src/hooks/schedulers/useInterval.ts create mode 100644 src/hooks/schedulers/useTimeout.ts delete mode 100644 src/hooks/useInterval.ts delete mode 100644 src/hooks/useTimeout.ts diff --git a/src/components/calls/group/GroupCallParticipantVideo.tsx b/src/components/calls/group/GroupCallParticipantVideo.tsx index 3ac61eb19..800fa8a12 100644 --- a/src/components/calls/group/GroupCallParticipantVideo.tsx +++ b/src/components/calls/group/GroupCallParticipantVideo.tsx @@ -19,8 +19,8 @@ import { fastRaf } from '../../../util/schedulers'; import { IS_CANVAS_FILTER_SUPPORTED } from '../../../util/windowEnvironment'; import formatGroupCallVolume from './helpers/formatGroupCallVolume'; +import useInterval from '../../../hooks/schedulers/useInterval'; import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers'; -import useInterval from '../../../hooks/useInterval'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useMenuPosition from '../../../hooks/useMenuPosition'; diff --git a/src/components/calls/phone/PhoneCall.tsx b/src/components/calls/phone/PhoneCall.tsx index 45880a095..d72d97220 100644 --- a/src/components/calls/phone/PhoneCall.tsx +++ b/src/components/calls/phone/PhoneCall.tsx @@ -23,10 +23,10 @@ import { import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets'; import renderText from '../../common/helpers/renderText'; +import useInterval from '../../../hooks/schedulers/useInterval'; import useAppLayout from '../../../hooks/useAppLayout'; import useFlag from '../../../hooks/useFlag'; import useForceUpdate from '../../../hooks/useForceUpdate'; -import useInterval from '../../../hooks/useInterval'; import useLang from '../../../hooks/useLang'; import AnimatedIcon from '../../common/AnimatedIcon'; @@ -137,9 +137,7 @@ const PhoneCall: FC = ({ const forceUpdate = useForceUpdate(); - useInterval(() => { - forceUpdate(); - }, isConnected ? 1000 : undefined); + useInterval(forceUpdate, isConnected ? 1000 : undefined); const callStatus = useMemo(() => { const state = phoneCall?.state; diff --git a/src/components/common/Composer.tsx b/src/components/common/Composer.tsx index 9d7412a36..c5221d467 100644 --- a/src/components/common/Composer.tsx +++ b/src/components/common/Composer.tsx @@ -105,12 +105,13 @@ import { getPeerColorClass } from './helpers/peerColor'; import renderText from './helpers/renderText'; import { getTextWithEntitiesAsHtml } from './helpers/renderTextWithEntities'; +import useInterval from '../../hooks/schedulers/useInterval'; +import useTimeout from '../../hooks/schedulers/useTimeout'; import useContextMenuHandlers from '../../hooks/useContextMenuHandlers'; import useDerivedState from '../../hooks/useDerivedState'; import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps'; import useFlag from '../../hooks/useFlag'; import useGetSelectionRange from '../../hooks/useGetSelectionRange'; -import useInterval from '../../hooks/useInterval'; import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; import usePrevious from '../../hooks/usePrevious'; @@ -120,7 +121,6 @@ import useShowTransition from '../../hooks/useShowTransition'; import useSignal from '../../hooks/useSignal'; import { useStateRef } from '../../hooks/useStateRef'; import useSyncEffect from '../../hooks/useSyncEffect'; -import useTimeout from '../../hooks/useTimeout'; import useAttachmentModal from '../middle/composer/hooks/useAttachmentModal'; import useBotCommandTooltip from '../middle/composer/hooks/useBotCommandTooltip'; import useClipboardPaste from '../middle/composer/hooks/useClipboardPaste'; diff --git a/src/components/common/PasswordForm.tsx b/src/components/common/PasswordForm.tsx index 28d5c4b89..b69171303 100644 --- a/src/components/common/PasswordForm.tsx +++ b/src/components/common/PasswordForm.tsx @@ -10,9 +10,9 @@ import buildClassName from '../../util/buildClassName'; import stopEvent from '../../util/stopEvent'; import { IS_TOUCH_ENV } from '../../util/windowEnvironment'; +import useTimeout from '../../hooks/schedulers/useTimeout'; import useAppLayout from '../../hooks/useAppLayout'; import useLang from '../../hooks/useLang'; -import useTimeout from '../../hooks/useTimeout'; import Button from '../ui/Button'; diff --git a/src/components/common/PasswordMonkey.tsx b/src/components/common/PasswordMonkey.tsx index eac191d4f..f751a39dc 100644 --- a/src/components/common/PasswordMonkey.tsx +++ b/src/components/common/PasswordMonkey.tsx @@ -4,9 +4,9 @@ import React, { memo, useCallback } from '../../lib/teact/teact'; import { STICKER_SIZE_AUTH, STICKER_SIZE_AUTH_MOBILE, STICKER_SIZE_TWO_FA } from '../../config'; import { LOCAL_TGS_URLS } from './helpers/animatedAssets'; +import useTimeout from '../../hooks/schedulers/useTimeout'; import useAppLayout from '../../hooks/useAppLayout'; import useFlag from '../../hooks/useFlag'; -import useTimeout from '../../hooks/useTimeout'; import AnimatedSticker from './AnimatedSticker'; diff --git a/src/components/left/main/StatusButton.tsx b/src/components/left/main/StatusButton.tsx index 9a2bc0aeb..b6145587a 100644 --- a/src/components/left/main/StatusButton.tsx +++ b/src/components/left/main/StatusButton.tsx @@ -8,10 +8,10 @@ import { EMOJI_STATUS_LOOP_LIMIT } from '../../../config'; import { selectUser } from '../../../global/selectors'; import { getServerTimeOffset } from '../../../util/serverTime'; +import useTimeout from '../../../hooks/schedulers/useTimeout'; import useAppLayout from '../../../hooks/useAppLayout'; import useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps'; import useFlag from '../../../hooks/useFlag'; -import useTimeout from '../../../hooks/useTimeout'; import CustomEmoji from '../../common/CustomEmoji'; import PremiumIcon from '../../common/PremiumIcon'; diff --git a/src/components/main/GameModal.tsx b/src/components/main/GameModal.tsx index b0ea54353..9722b219e 100644 --- a/src/components/main/GameModal.tsx +++ b/src/components/main/GameModal.tsx @@ -9,7 +9,7 @@ import { MAIN_THREAD_ID } from '../../api/types'; import { getCanPostInChat } from '../../global/helpers'; import { selectChat, selectChatFullInfo } from '../../global/selectors'; -import useInterval from '../../hooks/useInterval'; +import useInterval from '../../hooks/schedulers/useInterval'; import useLang from '../../hooks/useLang'; import useSendMessageAction from '../../hooks/useSendMessageAction'; diff --git a/src/components/main/LockScreen.tsx b/src/components/main/LockScreen.tsx index 63effc65f..a96ac904d 100644 --- a/src/components/main/LockScreen.tsx +++ b/src/components/main/LockScreen.tsx @@ -9,10 +9,10 @@ import type { GlobalState } from '../../global/types'; import { decryptSession } from '../../util/passcode'; import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets'; +import useTimeout from '../../hooks/schedulers/useTimeout'; import useFlag from '../../hooks/useFlag'; import useLang from '../../hooks/useLang'; import useShowTransition from '../../hooks/useShowTransition'; -import useTimeout from '../../hooks/useTimeout'; import AnimatedIconWithPreview from '../common/AnimatedIconWithPreview'; import PasswordForm from '../common/PasswordForm'; diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index b28b07c26..c0f90f773 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -49,15 +49,15 @@ import { parseInitialLocationHash, parseLocationHash } from '../../util/routing' import updateIcon from '../../util/updateIcon'; import { IS_ANDROID, IS_ELECTRON } from '../../util/windowEnvironment'; +import useInterval from '../../hooks/schedulers/useInterval'; +import useTimeout from '../../hooks/schedulers/useTimeout'; import useAppLayout from '../../hooks/useAppLayout'; import useForceUpdate from '../../hooks/useForceUpdate'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; -import useInterval from '../../hooks/useInterval'; import useLastCallback from '../../hooks/useLastCallback'; import usePreventPinchZoomGesture from '../../hooks/usePreventPinchZoomGesture'; import useShowTransition from '../../hooks/useShowTransition'; import useSyncEffect from '../../hooks/useSyncEffect'; -import useTimeout from '../../hooks/useTimeout'; import useBackgroundMode from '../../hooks/window/useBackgroundMode'; import useBeforeUnload from '../../hooks/window/useBeforeUnload'; import { useFullscreenStatus } from '../../hooks/window/useFullscreen'; diff --git a/src/components/mediaViewer/MediaViewerSlides.tsx b/src/components/mediaViewer/MediaViewerSlides.tsx index 5778485ba..87d2ca089 100644 --- a/src/components/mediaViewer/MediaViewerSlides.tsx +++ b/src/components/mediaViewer/MediaViewerSlides.tsx @@ -18,6 +18,7 @@ import { clamp, isBetween, round } from '../../util/math'; import { debounce } from '../../util/schedulers'; import { IS_IOS, IS_TOUCH_ENV } from '../../util/windowEnvironment'; +import useTimeout from '../../hooks/schedulers/useTimeout'; import useDebouncedCallback from '../../hooks/useDebouncedCallback'; import useDerivedState from '../../hooks/useDerivedState'; import useHistoryBack from '../../hooks/useHistoryBack'; @@ -25,7 +26,6 @@ import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; import useSignal from '../../hooks/useSignal'; import { useSignalRef } from '../../hooks/useSignalRef'; -import useTimeout from '../../hooks/useTimeout'; import { useFullscreenStatus } from '../../hooks/window/useFullscreen'; import useWindowSize from '../../hooks/window/useWindowSize'; import useControlsSignal from './hooks/useControlsSignal'; diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index 4fce360f8..43d548684 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -62,9 +62,9 @@ import { debounce, onTickEnd } from '../../util/schedulers'; import { groupMessages } from './helpers/groupMessages'; import { preventMessageInputBlur } from './helpers/preventMessageInputBlur'; +import useInterval from '../../hooks/schedulers/useInterval'; import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; -import useInterval from '../../hooks/useInterval'; import useLastCallback from '../../hooks/useLastCallback'; import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps'; import useNativeCopySelectedMessages from '../../hooks/useNativeCopySelectedMessages'; @@ -276,13 +276,13 @@ const MessageList: FC = ({ const ids = messageIds.filter((id) => { const message = messagesById[id]; - return message.reactions?.results.length && !message.content.action; + return message && message.reactions?.results.length && !message.content.action; }); if (!ids.length) return; loadMessageReactions({ chatId, ids }); - }, MESSAGE_REACTIONS_POLLING_INTERVAL); + }, MESSAGE_REACTIONS_POLLING_INTERVAL, true); useInterval(() => { if (!messageIds || !messagesById || type === 'scheduled') { @@ -317,7 +317,7 @@ const MessageList: FC = ({ if (!ids.length) return; loadMessageViews({ chatId, ids }); - }, MESSAGE_COMMENTS_POLLING_INTERVAL); + }, MESSAGE_COMMENTS_POLLING_INTERVAL, true); const loadMoreAround = useMemo(() => { if (type !== 'thread') { diff --git a/src/components/middle/message/InvoiceMediaPreview.tsx b/src/components/middle/message/InvoiceMediaPreview.tsx index 830a2d606..fb94178b2 100644 --- a/src/components/middle/message/InvoiceMediaPreview.tsx +++ b/src/components/middle/message/InvoiceMediaPreview.tsx @@ -9,7 +9,7 @@ import buildClassName from '../../../util/buildClassName'; import { formatMediaDuration } from '../../../util/dateFormat'; import { formatCurrency } from '../../../util/formatCurrency'; -import useInterval from '../../../hooks/useInterval'; +import useInterval from '../../../hooks/schedulers/useInterval'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; diff --git a/src/components/middle/message/Location.tsx b/src/components/middle/message/Location.tsx index 651e59756..184ff4695 100644 --- a/src/components/middle/message/Location.tsx +++ b/src/components/middle/message/Location.tsx @@ -20,13 +20,13 @@ import { } from '../../../util/map'; import { getServerTime } from '../../../util/serverTime'; +import useInterval from '../../../hooks/schedulers/useInterval'; +import useTimeout from '../../../hooks/schedulers/useTimeout'; import useForceUpdate from '../../../hooks/useForceUpdate'; -import useInterval from '../../../hooks/useInterval'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useMedia from '../../../hooks/useMedia'; import usePrevious from '../../../hooks/usePrevious'; -import useTimeout from '../../../hooks/useTimeout'; import Avatar from '../../common/Avatar'; import Skeleton from '../../ui/placeholder/Skeleton'; diff --git a/src/components/middle/message/SimilarChannels.tsx b/src/components/middle/message/SimilarChannels.tsx index aa80dcffe..fb40fbc5a 100644 --- a/src/components/middle/message/SimilarChannels.tsx +++ b/src/components/middle/message/SimilarChannels.tsx @@ -16,12 +16,12 @@ import buildClassName from '../../../util/buildClassName'; import { getAverageColor, rgb2hex } from '../../../util/colors'; import { formatIntegerCompact } from '../../../util/textFormat'; +import useTimeout from '../../../hooks/schedulers/useTimeout'; import useFlag from '../../../hooks/useFlag'; import useHorizontalScroll from '../../../hooks/useHorizontalScroll'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useMedia from '../../../hooks/useMedia'; -import useTimeout from '../../../hooks/useTimeout'; import Avatar from '../../common/Avatar'; import Icon from '../../common/Icon'; @@ -79,7 +79,7 @@ const SimilarChannels = ({ && areSimilarChannelsPresent, ); - useTimeout(() => setShoulRenderSkeleton(false), MAX_SKELETON_DELAY, []); + useTimeout(() => setShoulRenderSkeleton(false), MAX_SKELETON_DELAY); useEffect(() => { if (shoulRenderSkeleton && similarChannels && shouldShowInChat) { diff --git a/src/components/modals/webApp/WebAppModal.tsx b/src/components/modals/webApp/WebAppModal.tsx index 37053973e..fa8adaffc 100644 --- a/src/components/modals/webApp/WebAppModal.tsx +++ b/src/components/modals/webApp/WebAppModal.tsx @@ -22,9 +22,9 @@ import { extractCurrentThemeParams, validateHexColor } from '../../../util/theme import { callApi } from '../../../api/gramjs'; import renderText from '../../common/helpers/renderText'; +import useInterval from '../../../hooks/schedulers/useInterval'; import useAppLayout from '../../../hooks/useAppLayout'; import useFlag from '../../../hooks/useFlag'; -import useInterval from '../../../hooks/useInterval'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import usePrevious from '../../../hooks/usePrevious'; diff --git a/src/components/right/management/ManageInvites.tsx b/src/components/right/management/ManageInvites.tsx index c02000e78..b67e8de73 100644 --- a/src/components/right/management/ManageInvites.tsx +++ b/src/components/right/management/ManageInvites.tsx @@ -15,10 +15,10 @@ import { formatCountdown, MILLISECONDS_IN_DAY } from '../../../util/dateFormat'; import { getServerTime } from '../../../util/serverTime'; import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets'; +import useInterval from '../../../hooks/schedulers/useInterval'; import useFlag from '../../../hooks/useFlag'; import useForceUpdate from '../../../hooks/useForceUpdate'; import useHistoryBack from '../../../hooks/useHistoryBack'; -import useInterval from '../../../hooks/useInterval'; import useLang from '../../../hooks/useLang'; import AnimatedIcon from '../../common/AnimatedIcon'; @@ -92,9 +92,7 @@ const ManageInvites: FC = ({ )); }, [exportedInvites]); const forceUpdate = useForceUpdate(); - useInterval(() => { - forceUpdate(); - }, hasDetailedCountdown ? 1000 : undefined); + useInterval(forceUpdate, hasDetailedCountdown ? 1000 : undefined); const chatMainUsername = useMemo(() => chat && getMainUsername(chat), [chat]); const primaryInvite = exportedInvites?.find(({ isPermanent }) => isPermanent); diff --git a/src/components/ui/TextTimer.tsx b/src/components/ui/TextTimer.tsx index 05d42491e..cd96c1280 100644 --- a/src/components/ui/TextTimer.tsx +++ b/src/components/ui/TextTimer.tsx @@ -3,8 +3,8 @@ import React, { type FC, memo, useEffect } from '../../lib/teact/teact'; import { formatMediaDuration } from '../../util/dateFormat'; import { getServerTime } from '../../util/serverTime'; +import useInterval from '../../hooks/schedulers/useInterval'; import useForceUpdate from '../../hooks/useForceUpdate'; -import useInterval from '../../hooks/useInterval'; import useLang from '../../hooks/useLang'; type OwnProps = { diff --git a/src/hooks/schedulers/useInterval.ts b/src/hooks/schedulers/useInterval.ts new file mode 100644 index 000000000..b58293ffa --- /dev/null +++ b/src/hooks/schedulers/useInterval.ts @@ -0,0 +1,20 @@ +import { useEffect } from '../../lib/teact/teact'; + +import useLastCallback from '../useLastCallback'; + +function useInterval(callback: NoneToVoidFunction, delay?: number, noFirst = false) { + const savedCallback = useLastCallback(callback); + + useEffect(() => { + if (delay === undefined) { + return undefined; + } + + const id = setInterval(() => savedCallback(), delay); + if (!noFirst) savedCallback(); + + return () => clearInterval(id); + }, [delay, noFirst]); +} + +export default useInterval; diff --git a/src/hooks/schedulers/useTimeout.ts b/src/hooks/schedulers/useTimeout.ts new file mode 100644 index 000000000..66c27fc94 --- /dev/null +++ b/src/hooks/schedulers/useTimeout.ts @@ -0,0 +1,18 @@ +import { useEffect } from '../../lib/teact/teact'; + +import useLastCallback from '../useLastCallback'; + +function useTimeout(callback: NoneToVoidFunction, delay?: number) { + const savedCallback = useLastCallback(callback); + + useEffect(() => { + if (typeof delay !== 'number') { + return undefined; + } + + const id = setTimeout(() => savedCallback(), delay); + return () => clearTimeout(id); + }, [delay]); +} + +export default useTimeout; diff --git a/src/hooks/useInterval.ts b/src/hooks/useInterval.ts deleted file mode 100644 index e85f41bab..000000000 --- a/src/hooks/useInterval.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect, useLayoutEffect, useRef } from '../lib/teact/teact'; - -function useInterval(callback: NoneToVoidFunction, delay?: number, noFirst = false) { - const savedCallback = useRef(callback); - - useLayoutEffect(() => { - savedCallback.current = callback; - }, [callback]); - - useEffect(() => { - if (delay === undefined) { - return undefined; - } - - const id = setInterval(() => savedCallback.current(), delay); - if (!noFirst) savedCallback.current(); - - return () => clearInterval(id); - }, [delay, noFirst]); -} - -export default useInterval; diff --git a/src/hooks/useTimeout.ts b/src/hooks/useTimeout.ts deleted file mode 100644 index 4053bf226..000000000 --- a/src/hooks/useTimeout.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useEffect } from '../lib/teact/teact'; - -import useLastCallback from './useLastCallback'; - -function useTimeout(callback: () => void, delay?: number, dependencies: readonly any[] = []) { - const savedCallback = useLastCallback(callback); - - useEffect(() => { - if (typeof delay !== 'number') { - return undefined; - } - - const id = setTimeout(() => savedCallback(), delay); - return () => clearTimeout(id); - // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps - }, [delay, savedCallback, ...dependencies]); -} - -export default useTimeout;