From ddd5672767f99cd093a497ebd0c7b8f4b959deba Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 4 Nov 2024 17:44:35 +0100 Subject: [PATCH 01/17] Fix AuthScreens component --- src/hooks/useEffectOnce.ts | 17 ++++++++++ .../Navigation/AppNavigator/AuthScreens.tsx | 34 ++++++------------- 2 files changed, 28 insertions(+), 23 deletions(-) create mode 100644 src/hooks/useEffectOnce.ts diff --git a/src/hooks/useEffectOnce.ts b/src/hooks/useEffectOnce.ts new file mode 100644 index 000000000000..eac42ef46459 --- /dev/null +++ b/src/hooks/useEffectOnce.ts @@ -0,0 +1,17 @@ +import type {EffectCallback} from 'react'; +import {useEffect, useRef} from 'react'; + +function useEffectOnce(callback: EffectCallback, condition = true) { + const hasRunCallbackBefore = useRef(false); + + useEffect(() => { + if (!condition || hasRunCallbackBefore.current === true) { + return; + } + + hasRunCallbackBefore.current = true; + callback(); + }, [condition, callback]); +} + +export default useEffectOnce; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 58586250f958..fe9c158e063b 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -11,6 +11,7 @@ import {useSearchRouterContext} from '@components/Search/SearchRouter/SearchRout import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal'; import TestToolsModal from '@components/TestToolsModal'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; +import useEffectOnce from '@hooks/useEffectOnce'; import useOnboardingFlowRouter from '@hooks/useOnboardingFlow'; import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -234,7 +235,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const {activeWorkspaceID} = useActiveWorkspace(); const {toggleSearchRouter} = useSearchRouterContext(); - const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); + const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [onboardingIsMediumOrLargerScreenWidth, screenOptions]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), [StyleUtils, shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, styles], @@ -242,35 +243,25 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const modal = useRef({}); const [didPusherInit, setDidPusherInit] = useState(false); const {isOnboardingCompleted} = useOnboardingFlowRouter(); - - let initialReportID: string | undefined; - const isInitialRender = useRef(true); - - // eslint-disable-next-line react-compiler/react-compiler - if (isInitialRender.current) { + const [initialReportID] = useState(() => { Timing.start(CONST.TIMING.HOMEPAGE_INITIAL_RENDER); const currentURL = getCurrentUrl(); - if (currentURL) { - initialReportID = new URL(currentURL).pathname.match(CONST.REGEX.REPORT_ID_FROM_PATH)?.at(1); + const reportIdFromPath = currentURL && new URL(currentURL).pathname.match(CONST.REGEX.REPORT_ID_FROM_PATH)?.at(1); + if (reportIdFromPath) { + return reportIdFromPath; } - if (!initialReportID) { - const initialReport = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom(), activeWorkspaceID); - initialReportID = initialReport?.reportID ?? ''; - } - - // eslint-disable-next-line react-compiler/react-compiler - isInitialRender.current = false; - } + const initialReport = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom(), activeWorkspaceID); + return initialReport?.reportID ?? ''; + }); const isOnboardingCompletedRef = useRef(isOnboardingCompleted); - useEffect(() => { isOnboardingCompletedRef.current = isOnboardingCompleted; }, [isOnboardingCompleted]); - useEffect(() => { + useEffectOnce(() => { const shortcutsOverviewShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUTS; const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH; const chatShortcutConfig = CONST.KEYBOARD_SHORTCUTS.NEW_CHAT; @@ -406,10 +397,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie unsubscribeDebugShortcut(); Session.cleanupSession(); }; - - // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, []); + }); const CentralPaneScreenOptions = { headerShown: false, From 692c16ad40b4a43a424fc3c6f4ab17df59f05dcd Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 4 Nov 2024 17:44:50 +0100 Subject: [PATCH 02/17] Remove redundant useEffect --- src/pages/workspace/members/WorkspaceOwnerChangeCheck.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeCheck.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeCheck.tsx index 344aafeedde6..83458c3ad74a 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeCheck.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeCheck.tsx @@ -52,11 +52,6 @@ function WorkspaceOwnerChangeCheck({personalDetails, policy, accountID, error}: setDisplayTexts(texts); }, [accountID, error, personalDetails, policy, translate]); - useEffect(() => { - updateDisplayTexts(); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, []); - useEffect(() => { updateDisplayTexts(); }, [updateDisplayTexts]); From d1567332015b0afd4a776bc6aee236b96a342ecc Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 4 Nov 2024 17:48:15 +0100 Subject: [PATCH 03/17] Pass transactions to getAllReportTransactions --- src/components/MoneyReportHeader.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index c94938c3d103..e1e4a3e043f5 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -103,8 +103,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const [isHoldMenuVisible, setIsHoldMenuVisible] = useState(false); const [paymentType, setPaymentType] = useState(); const [requestType, setRequestType] = useState(); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - const allTransactions = useMemo(() => TransactionUtils.getAllReportTransactions(moneyRequestReport?.reportID), [moneyRequestReport?.reportID, transactions]); + const allTransactions = useMemo(() => TransactionUtils.getAllReportTransactions(moneyRequestReport?.reportID, transactions), [moneyRequestReport?.reportID, transactions]); const canAllowSettlement = ReportUtils.hasUpdatedTotal(moneyRequestReport, policy); const policyType = policy?.type; const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport); From 77655bca5fb43aaf273910151b779d805c9ccff7 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 4 Nov 2024 22:35:16 +0100 Subject: [PATCH 04/17] Fix reassigning a variable in component --- .../AttachmentViewPdf/index.android.tsx | 1 - .../Reactions/ReportActionItemEmojiReactions.tsx | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx index c6e7984b793f..108d1b8ea93b 100644 --- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx +++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx @@ -41,7 +41,6 @@ function AttachmentViewPdf(props: AttachmentViewPdfProps) { // enable the pager scroll so that the user // can swipe to the next attachment otherwise disable it. if (translateX > translateY && translateX > SCROLL_THRESHOLD && allowEnablingScroll) { - // eslint-disable-next-line react-compiler/react-compiler isScrollEnabled.value = true; } else if (translateY > SCROLL_THRESHOLD) { isScrollEnabled.value = false; diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.tsx b/src/components/Reactions/ReportActionItemEmojiReactions.tsx index bc5f48f9001c..f4f67f983781 100644 --- a/src/components/Reactions/ReportActionItemEmojiReactions.tsx +++ b/src/components/Reactions/ReportActionItemEmojiReactions.tsx @@ -88,8 +88,6 @@ function ReportActionItemEmojiReactions({ const reactionListRef = useContext(ReactionListContext); const popoverReactionListAnchors = useRef({}); - let totalReactionCount = 0; - const reportActionID = reportAction.reportActionID; // Each emoji is sorted by the oldest timestamp of user reactions so that they will always appear in the same order for everyone @@ -104,8 +102,6 @@ function ReportActionItemEmojiReactions({ if (reactionCount === 0) { return null; } - // eslint-disable-next-line react-compiler/react-compiler - totalReactionCount += reactionCount; const onPress = () => { toggleReaction(emoji, true); @@ -130,6 +126,13 @@ function ReportActionItemEmojiReactions({ ['oldestTimestamp'], ); + const totalReactionCount = formattedReactions.reduce((prev, curr) => { + if (curr === null) { + return prev + 0; + } + return prev + curr.reactionCount; + }, 0); + return ( totalReactionCount > 0 && ( From 5f5773cf9a9f1e6945a9697f15f9dd6e988154a3 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 09:45:59 +0100 Subject: [PATCH 05/17] Fix two bugs related to useEffect cleanup func --- src/hooks/useWindowDimensions/index.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index 4997fc4b01a7..b8f77b42037e 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -61,10 +61,11 @@ export default function (useCachedViewportHeight = false): WindowDimensions { if (!isCachedViewportHeight) { return; } - window.addEventListener('focusin', handleFocusIn.current); + + const handleFocusInValue = handleFocusIn.current; + window.addEventListener('focusin', handleFocusInValue); return () => { - // eslint-disable-next-line react-hooks/exhaustive-deps - window.removeEventListener('focusin', handleFocusIn.current); + window.removeEventListener('focusin', handleFocusInValue); }; }, [isCachedViewportHeight]); @@ -79,10 +80,11 @@ export default function (useCachedViewportHeight = false): WindowDimensions { if (!isCachedViewportHeight) { return; } - window.addEventListener('focusout', handleFocusOut.current); + + const handleFocusOutValue = handleFocusOut.current; + window.addEventListener('focusout', handleFocusOutValue); return () => { - // eslint-disable-next-line react-hooks/exhaustive-deps - window.removeEventListener('focusout', handleFocusOut.current); + window.removeEventListener('focusout', handleFocusOutValue); }; }, [isCachedViewportHeight]); @@ -91,7 +93,7 @@ export default function (useCachedViewportHeight = false): WindowDimensions { return; } setCachedViewportHeight(windowHeight); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [windowHeight, isCachedViewportHeight]); useEffect(() => { From a3c9faeeccfffd3a2eb3d6628b0921745a6026e5 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 09:47:49 +0100 Subject: [PATCH 06/17] Fix Unexpected terminal kind for ternary test block --- src/pages/TransactionReceiptPage.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/TransactionReceiptPage.tsx b/src/pages/TransactionReceiptPage.tsx index 86f7c99b91bc..d868b6535745 100644 --- a/src/pages/TransactionReceiptPage.tsx +++ b/src/pages/TransactionReceiptPage.tsx @@ -52,9 +52,8 @@ function TransactionReceipt({route}: TransactionReceiptProps) { if (secondToLastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR) { Navigation.dismissModal(); } else { - Navigation.dismissModal( - ReportUtils.isOneTransactionThread(report?.reportID ?? '-1', report?.parentReportID ?? '-1', parentReportAction) ? report?.parentReportID : report?.reportID, - ); + const isOneTransactionThread = ReportUtils.isOneTransactionThread(report?.reportID ?? '-1', report?.parentReportID ?? '-1', parentReportAction); + Navigation.dismissModal(isOneTransactionThread ? report?.parentReportID : report?.reportID); } }; From 49f0f59393a0a3dc13f3fe5b548cb76d40c03529 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 09:53:49 +0100 Subject: [PATCH 07/17] Fix Unexpected terminal kind for logical test block --- src/pages/iou/SplitBillDetailsPage.tsx | 5 +++-- .../accounting/intacct/advanced/SageIntacctAdvancedPage.tsx | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index bb464e521407..fd26504b73a2 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -56,12 +56,13 @@ function SplitBillDetailsPage({route, report, reportAction}: SplitBillDetailsPag } else { participants = participantAccountIDs.map((accountID) => OptionsListUtils.getParticipantsOption({accountID, selected: true, reportID: ''}, personalDetails)); } - const payeePersonalDetails = personalDetails?.[reportAction?.actorAccountID ?? -1]; + const actorAccountID = reportAction?.actorAccountID ?? -1; + const payeePersonalDetails = personalDetails?.[actorAccountID]; const participantsExcludingPayee = participants.filter((participant) => participant.accountID !== reportAction?.actorAccountID); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); const hasSmartScanFailed = TransactionUtils.hasReceipt(transaction) && transaction?.receipt?.state === CONST.IOU.RECEIPT_STATE.SCANFAILED; - const isEditingSplitBill = session?.accountID === reportAction?.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); + const isEditingSplitBill = session?.accountID === actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); const [isConfirmed, setIsConfirmed] = useState(false); const { diff --git a/src/pages/workspace/accounting/intacct/advanced/SageIntacctAdvancedPage.tsx b/src/pages/workspace/accounting/intacct/advanced/SageIntacctAdvancedPage.tsx index 5a0df17fc92c..2d2480835f6e 100644 --- a/src/pages/workspace/accounting/intacct/advanced/SageIntacctAdvancedPage.tsx +++ b/src/pages/workspace/accounting/intacct/advanced/SageIntacctAdvancedPage.tsx @@ -119,7 +119,7 @@ function SageIntacctAdvancedPage({policy}: WithPolicyProps) { pendingAction={settingsPendingAction([CONST.SAGE_INTACCT_CONFIG.REIMBURSEMENT_ACCOUNT_ID], pendingFields)} > Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PAYMENT_ACCOUNT.getRoute(policyID))} From bbc3945563fedf3fed0c5ea7d69f12f618c5552e Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 10:54:18 +0100 Subject: [PATCH 08/17] Clean in useEffectOnce function --- src/hooks/useEffectOnce.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useEffectOnce.ts b/src/hooks/useEffectOnce.ts index eac42ef46459..07b302cb7d28 100644 --- a/src/hooks/useEffectOnce.ts +++ b/src/hooks/useEffectOnce.ts @@ -10,7 +10,7 @@ function useEffectOnce(callback: EffectCallback, condition = true) { } hasRunCallbackBefore.current = true; - callback(); + return callback(); }, [condition, callback]); } From 6f85fe37fd59d27848459b25c91dc03dd31b84ff Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 11:16:30 +0100 Subject: [PATCH 09/17] Add explanation to useEffectOnce --- src/hooks/useEffectOnce.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hooks/useEffectOnce.ts b/src/hooks/useEffectOnce.ts index 07b302cb7d28..0b167281e205 100644 --- a/src/hooks/useEffectOnce.ts +++ b/src/hooks/useEffectOnce.ts @@ -1,6 +1,12 @@ import type {EffectCallback} from 'react'; import {useEffect, useRef} from 'react'; +/** + * This hook is used to run an effect only once, usually on the first render (on mount). + * + * @param callback The side effect to run only once. + * @param condition Run the callback if this condition is true. Defaults to true. + */ function useEffectOnce(callback: EffectCallback, condition = true) { const hasRunCallbackBefore = useRef(false); From b840df5f50cfc2e1ac5f00cbe8c51992da6395c6 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 11:19:41 +0100 Subject: [PATCH 10/17] Revert one comment --- .../AttachmentView/AttachmentViewPdf/index.android.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx index 108d1b8ea93b..c6e7984b793f 100644 --- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx +++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.tsx @@ -41,6 +41,7 @@ function AttachmentViewPdf(props: AttachmentViewPdfProps) { // enable the pager scroll so that the user // can swipe to the next attachment otherwise disable it. if (translateX > translateY && translateX > SCROLL_THRESHOLD && allowEnablingScroll) { + // eslint-disable-next-line react-compiler/react-compiler isScrollEnabled.value = true; } else if (translateY > SCROLL_THRESHOLD) { isScrollEnabled.value = false; From 224dac2d65d999099b6c2881cca1e3dd67166738 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 16:22:39 +0100 Subject: [PATCH 11/17] Revert "Fix patches" This reverts commit a8f6e51567e81aced27c9d842fc0ff18dbe363c3. --- ...native-reanimated+3.15.1+001+hybrid-app.patch} | 4 ++-- ...imated+3.15.1+002+dontWhitelistTextProp.patch} | 0 ...ive-reanimated+3.15.1+003+fixNullViewTag.patch | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) rename patches/{react-native-reanimated+3.16.1+001+hybrid-app.patch => react-native-reanimated+3.15.1+001+hybrid-app.patch} (91%) rename patches/{react-native-reanimated+3.16.1+002+dontWhitelistTextProp.patch => react-native-reanimated+3.15.1+002+dontWhitelistTextProp.patch} (100%) create mode 100644 patches/react-native-reanimated+3.15.1+003+fixNullViewTag.patch diff --git a/patches/react-native-reanimated+3.16.1+001+hybrid-app.patch b/patches/react-native-reanimated+3.15.1+001+hybrid-app.patch similarity index 91% rename from patches/react-native-reanimated+3.16.1+001+hybrid-app.patch rename to patches/react-native-reanimated+3.15.1+001+hybrid-app.patch index 835df1f034a9..3b40360d5860 100644 --- a/patches/react-native-reanimated+3.16.1+001+hybrid-app.patch +++ b/patches/react-native-reanimated+3.15.1+001+hybrid-app.patch @@ -1,9 +1,9 @@ diff --git a/node_modules/react-native-reanimated/scripts/reanimated_utils.rb b/node_modules/react-native-reanimated/scripts/reanimated_utils.rb -index 9fc7b15..e453d84 100644 +index af0935f..ccd2a9e 100644 --- a/node_modules/react-native-reanimated/scripts/reanimated_utils.rb +++ b/node_modules/react-native-reanimated/scripts/reanimated_utils.rb @@ -17,7 +17,11 @@ def find_config() - :react_native_reanimated_dir_from_pods_root => nil, + :react_native_common_dir => nil, } - react_native_node_modules_dir = File.join(File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native/package.json')"`), '..') diff --git a/patches/react-native-reanimated+3.16.1+002+dontWhitelistTextProp.patch b/patches/react-native-reanimated+3.15.1+002+dontWhitelistTextProp.patch similarity index 100% rename from patches/react-native-reanimated+3.16.1+002+dontWhitelistTextProp.patch rename to patches/react-native-reanimated+3.15.1+002+dontWhitelistTextProp.patch diff --git a/patches/react-native-reanimated+3.15.1+003+fixNullViewTag.patch b/patches/react-native-reanimated+3.15.1+003+fixNullViewTag.patch new file mode 100644 index 000000000000..ca982c6f8036 --- /dev/null +++ b/patches/react-native-reanimated+3.15.1+003+fixNullViewTag.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx b/node_modules/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx +index 577b4a7..c60f0f8 100644 +--- a/node_modules/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx ++++ b/node_modules/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx +@@ -481,7 +481,9 @@ export function createAnimatedComponent( + ? (ref as HTMLElement) + : findNodeHandle(ref as Component); + +- this._componentViewTag = tag as number; ++ if (tag !== null) { ++ this._componentViewTag = tag as number; ++ } + + const { layout, entering, exiting, sharedTransitionTag } = this.props; + if ( From 6b57db3dcf2481a0b718c39f269b01f4b3083bb8 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 16:26:45 +0100 Subject: [PATCH 12/17] Remove useEffectOnce as it doesn't work as expected --- src/hooks/useEffectOnce.ts | 23 ------------------- .../Navigation/AppNavigator/AuthScreens.tsx | 7 ++++-- 2 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 src/hooks/useEffectOnce.ts diff --git a/src/hooks/useEffectOnce.ts b/src/hooks/useEffectOnce.ts deleted file mode 100644 index 0b167281e205..000000000000 --- a/src/hooks/useEffectOnce.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type {EffectCallback} from 'react'; -import {useEffect, useRef} from 'react'; - -/** - * This hook is used to run an effect only once, usually on the first render (on mount). - * - * @param callback The side effect to run only once. - * @param condition Run the callback if this condition is true. Defaults to true. - */ -function useEffectOnce(callback: EffectCallback, condition = true) { - const hasRunCallbackBefore = useRef(false); - - useEffect(() => { - if (!condition || hasRunCallbackBefore.current === true) { - return; - } - - hasRunCallbackBefore.current = true; - return callback(); - }, [condition, callback]); -} - -export default useEffectOnce; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index fe9c158e063b..c2b56b0fb50c 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -261,7 +261,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie isOnboardingCompletedRef.current = isOnboardingCompleted; }, [isOnboardingCompleted]); - useEffectOnce(() => { + useEffect(() => { const shortcutsOverviewShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUTS; const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH; const chatShortcutConfig = CONST.KEYBOARD_SHORTCUTS.NEW_CHAT; @@ -397,7 +397,10 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie unsubscribeDebugShortcut(); Session.cleanupSession(); }; - }); + + // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, []); const CentralPaneScreenOptions = { headerShown: false, From 018dfc94af2213e593cc4ebb40b714a8e6bf91f7 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 16:27:23 +0100 Subject: [PATCH 13/17] Remove useEffectOnce import --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index c2b56b0fb50c..5fae96d21110 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -11,7 +11,6 @@ import {useSearchRouterContext} from '@components/Search/SearchRouter/SearchRout import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal'; import TestToolsModal from '@components/TestToolsModal'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; -import useEffectOnce from '@hooks/useEffectOnce'; import useOnboardingFlowRouter from '@hooks/useOnboardingFlow'; import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; From d95f9ea5f7b5d0ec3b9868a39c9381c8d92c118c Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 16:54:02 +0100 Subject: [PATCH 14/17] Ignore react-compiler the correct way --- src/components/ConnectToNetSuiteFlow/index.tsx | 3 +-- .../ConnectToQuickbooksDesktopFlow/index.native.tsx | 3 +-- .../ConnectToQuickbooksOnlineFlow/index.native.tsx | 3 +-- src/components/ConnectToQuickbooksOnlineFlow/index.tsx | 3 +-- src/components/ConnectToSageIntacctFlow/index.tsx | 3 +-- src/components/ConnectToXeroFlow/index.native.tsx | 3 +-- src/components/ConnectToXeroFlow/index.tsx | 3 +-- .../AppNavigator/useNavigationResetOnLayoutChange.ts | 3 +-- .../UpdateDelegateRole/UpdateDelegateRolePage.tsx | 3 +-- src/pages/settings/Security/SecuritySettingsPage.tsx | 6 ++---- 10 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/components/ConnectToNetSuiteFlow/index.tsx b/src/components/ConnectToNetSuiteFlow/index.tsx index 5eb548c2acb5..1d33eb07df4f 100644 --- a/src/components/ConnectToNetSuiteFlow/index.tsx +++ b/src/components/ConnectToNetSuiteFlow/index.tsx @@ -53,8 +53,7 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) { return; } setIsReuseConnectionsPopoverOpen(true); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); if (threeDotsMenuContainerRef) { diff --git a/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx b/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx index 96c2c75183d9..afe27aa704e4 100644 --- a/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx +++ b/src/components/ConnectToQuickbooksDesktopFlow/index.native.tsx @@ -6,8 +6,7 @@ import type {ConnectToQuickbooksDesktopFlowProps} from './types'; function ConnectToQuickbooksDesktopFlow({policyID}: ConnectToQuickbooksDesktopFlowProps) { useEffect(() => { Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL.getRoute(policyID)); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); return null; diff --git a/src/components/ConnectToQuickbooksOnlineFlow/index.native.tsx b/src/components/ConnectToQuickbooksOnlineFlow/index.native.tsx index a6659338451e..497c2f91e767 100644 --- a/src/components/ConnectToQuickbooksOnlineFlow/index.native.tsx +++ b/src/components/ConnectToQuickbooksOnlineFlow/index.native.tsx @@ -32,8 +32,7 @@ function ConnectToQuickbooksOnlineFlow({policyID, session}: ConnectToQuickbooksO // Since QBO doesn't support Taxes, we should disable them from the LHN when connecting to QBO PolicyAction.enablePolicyTaxes(policyID, false); setWebViewOpen(true); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); if (isWebViewOpen) { diff --git a/src/components/ConnectToQuickbooksOnlineFlow/index.tsx b/src/components/ConnectToQuickbooksOnlineFlow/index.tsx index 6b825240ba6d..d934d891ad63 100644 --- a/src/components/ConnectToQuickbooksOnlineFlow/index.tsx +++ b/src/components/ConnectToQuickbooksOnlineFlow/index.tsx @@ -12,8 +12,7 @@ function ConnectToQuickbooksOnlineFlow({policyID}: ConnectToQuickbooksOnlineFlow // Since QBO doesn't support Taxes, we should disable them from the LHN when connecting to QBO PolicyAction.enablePolicyTaxes(policyID, false); Link.openLink(getQuickbooksOnlineSetupLink(policyID), environmentURL); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); return null; diff --git a/src/components/ConnectToSageIntacctFlow/index.tsx b/src/components/ConnectToSageIntacctFlow/index.tsx index 20ed6fa79ebc..f93fce9c668a 100644 --- a/src/components/ConnectToSageIntacctFlow/index.tsx +++ b/src/components/ConnectToSageIntacctFlow/index.tsx @@ -58,8 +58,7 @@ function ConnectToSageIntacctFlow({policyID}: ConnectToSageIntacctFlowProps) { return; } setIsReuseConnectionsPopoverOpen(true); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); if (threeDotsMenuContainerRef) { diff --git a/src/components/ConnectToXeroFlow/index.native.tsx b/src/components/ConnectToXeroFlow/index.native.tsx index fbf7bf01ab5c..6c9adfe8dbd7 100644 --- a/src/components/ConnectToXeroFlow/index.native.tsx +++ b/src/components/ConnectToXeroFlow/index.native.tsx @@ -34,8 +34,7 @@ function ConnectToXeroFlow({policyID}: ConnectToXeroFlowProps) { return; } setWebViewOpen(true); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); return ( diff --git a/src/components/ConnectToXeroFlow/index.tsx b/src/components/ConnectToXeroFlow/index.tsx index ad41ba8082b1..7ed2c73ba348 100644 --- a/src/components/ConnectToXeroFlow/index.tsx +++ b/src/components/ConnectToXeroFlow/index.tsx @@ -25,8 +25,7 @@ function ConnectToXeroFlow({policyID}: ConnectToXeroFlowProps) { return; } Link.openLink(getXeroSetupLink(policyID), environmentURL); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); if (!is2FAEnabled) { diff --git a/src/libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange.ts b/src/libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange.ts index 79ea32f9de2a..99d0b91bff76 100644 --- a/src/libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange.ts +++ b/src/libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange.ts @@ -12,8 +12,7 @@ function useNavigationResetOnLayoutChange({navigation}: CustomEffectsHookProps) } // We need to separately reset state of this navigator to trigger getRehydratedState. navigation.reset(navigation.getState()); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [shouldUseNarrowLayout]); } diff --git a/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx index 58b1b710d474..1ac362a50457 100644 --- a/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx +++ b/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx @@ -35,8 +35,7 @@ function UpdateDelegateRolePage({route}: UpdateDelegateRolePageProps) { useEffect(() => { updateDelegateRoleOptimistically(login ?? '', currentRole as DelegateRole); return () => clearDelegateRolePendingAction(login); - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [login]); return ( diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index cd8e7c14d882..ac66c368f631 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -176,8 +176,7 @@ function SecuritySettingsPage() { onPress, }; }), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps [delegates, translate, styles, personalDetails, errorFields], ); @@ -199,8 +198,7 @@ function SecuritySettingsPage() { interactive: false, }; }), - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps [delegators, styles, translate, personalDetails], ); From 0656a487d9b87978dc9aa3c8ba868af02953a9c4 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 5 Nov 2024 16:57:55 +0100 Subject: [PATCH 15/17] Don't use ref anymore to track previous result on search page --- src/components/Search/index.tsx | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9238488361b0..636bc14ea18e 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -1,9 +1,8 @@ import {useIsFocused, useNavigation} from '@react-navigation/native'; import type {StackNavigationProp} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import type {NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import SearchTableHeader from '@components/SelectionList/SearchTableHeader'; @@ -95,7 +94,7 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr const {isSmallScreenWidth, isLargeScreenWidth} = useResponsiveLayout(); const navigation = useNavigation>(); const isFocused = useIsFocused(); - const lastSearchResultsRef = useRef>(); + const [lastNonEmptySearchResults, setLastNonEmptySearchResults] = useState(undefined); const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading, lastSearchType, setLastSearchType} = useSearchContext(); const {selectionMode} = useMobileSelectionMode(false); @@ -111,7 +110,11 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr if (!currentSearchResults?.search?.type) { return; } + setLastSearchType(currentSearchResults.search.type); + if (currentSearchResults.data) { + setLastNonEmptySearchResults(currentSearchResults); + } }, [lastSearchType, queryJSON, setLastSearchType, currentSearchResults]); const canSelectMultiple = isSmallScreenWidth ? !!selectionMode?.isEnabled : true; @@ -171,15 +174,7 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr }, }); - // save last non-empty search results to avoid ugly flash of loading screen when hash changes and onyx returns empty data - // eslint-disable-next-line react-compiler/react-compiler - if (currentSearchResults?.data && currentSearchResults !== lastSearchResultsRef.current) { - // eslint-disable-next-line react-compiler/react-compiler - lastSearchResultsRef.current = currentSearchResults; - } - - // eslint-disable-next-line react-compiler/react-compiler - const searchResults = currentSearchResults?.data ? currentSearchResults : lastSearchResultsRef.current; + const searchResults = currentSearchResults?.data ? currentSearchResults : lastNonEmptySearchResults; const {newSearchResultKey, handleSelectionListScroll} = useSearchHighlightAndScroll({ searchResults, From 251477808546c35c0289dcc56ef9ca43268336dc Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 13 Nov 2024 16:23:49 +0100 Subject: [PATCH 16/17] Fix how totalReactionCount is calculated --- .../Reactions/ReportActionItemEmojiReactions.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.tsx b/src/components/Reactions/ReportActionItemEmojiReactions.tsx index f4f67f983781..9c3ae5a8b5c6 100644 --- a/src/components/Reactions/ReportActionItemEmojiReactions.tsx +++ b/src/components/Reactions/ReportActionItemEmojiReactions.tsx @@ -126,12 +126,7 @@ function ReportActionItemEmojiReactions({ ['oldestTimestamp'], ); - const totalReactionCount = formattedReactions.reduce((prev, curr) => { - if (curr === null) { - return prev + 0; - } - return prev + curr.reactionCount; - }, 0); + const totalReactionCount = formattedReactions.reduce((prev, curr) => (curr === null ? prev : prev + curr.reactionCount), 0); return ( totalReactionCount > 0 && ( From 6ef11970e80bc7eed58de40e42420a75c336c4f7 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 13 Nov 2024 16:24:01 +0100 Subject: [PATCH 17/17] Bring back old code --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 4b2af01af1ee..7a556cfbf82e 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -233,7 +233,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const {activeWorkspaceID} = useActiveWorkspace(); const {toggleSearchRouter} = useSearchRouterContext(); - const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [onboardingIsMediumOrLargerScreenWidth, screenOptions]); + const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), [StyleUtils, shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, styles],