diff --git a/components/HandOffComponent.ios.tsx b/components/HandOffComponent.ios.tsx index 8e726a59e..a0b6365d0 100644 --- a/components/HandOffComponent.ios.tsx +++ b/components/HandOffComponent.ios.tsx @@ -7,18 +7,24 @@ import { GROUP_IO_BLUEWALLET } from '../blue_modules/currency'; import { BlueApp } from '../class'; import { HandOffComponentProps } from './types'; -const HandOffComponent: React.FC = props => { - const { isHandOffUseEnabled } = useSettings(); - if (!props || !props.type || !props.userInfo || Object.keys(props.userInfo).length === 0) { - console.debug('HandOffComponent: Missing required type or userInfo data'); - return null; - } - const userInfo = JSON.stringify(props.userInfo); - console.debug(`HandOffComponent is rendering. Type: ${props.type}, UserInfo: ${userInfo}...`); - return isHandOffUseEnabled ? : null; -}; +const HandOffComponent: React.FC = React.memo( + props => { + const { isHandOffUseEnabled } = useSettings(); -const MemoizedHandOffComponent = React.memo(HandOffComponent); + if (!props || !props.type || !props.userInfo || Object.keys(props.userInfo).length === 0) { + return null; + } + + return isHandOffUseEnabled ? : null; + }, + (prevProps, nextProps) => { + return ( + prevProps.type === nextProps.type && + JSON.stringify(prevProps.userInfo) === JSON.stringify(nextProps.userInfo) && + prevProps.title === nextProps.title + ); + }, +); export const setIsHandOffUseEnabled = async (value: boolean) => { try { @@ -44,4 +50,4 @@ export const getIsHandOffUseEnabled = async (): Promise => { } }; -export default MemoizedHandOffComponent; +export default HandOffComponent; diff --git a/screen/receive/details.js b/screen/receive/details.js index 94c49a440..9830a32b2 100644 --- a/screen/receive/details.js +++ b/screen/receive/details.js @@ -42,6 +42,37 @@ import TipBox from '../../components/TipBox'; const segmentControlValues = [loc.wallets.details_address, loc.bip47.payment_code]; +const TabContent = React.memo( + ({ currentTab, bip21encoded, wallet, address, showAddress, isCustom, handleShareButtonPressed, renderReceiveDetails }) => { + const qrValue = useMemo( + () => (currentTab === segmentControlValues[0] ? bip21encoded : wallet?.getBIP47PaymentCode()), + [currentTab, bip21encoded, wallet], + ); + + if (currentTab === segmentControlValues[0]) { + return {address && renderReceiveDetails()}; + } else { + return ( + + {!qrValue && {loc.bip47.not_found}} + {qrValue && ( + <> + + + + + )} + + ); + } + }, +); + +const MemoizedHandoffComponent = React.memo( + ({ address }) => , + (prevProps, nextProps) => prevProps.address === nextProps.address, +); + const ReceiveDetails = () => { const { walletID, address } = useRoute().params; const { wallets, saveToDisk, sleep, fetchAndSaveWalletTransactions } = useStorage(); @@ -459,25 +490,37 @@ const ReceiveDetails = () => { } }; - const renderTabContent = () => { - const qrValue = currentTab === segmentControlValues[0] ? bip21encoded : wallet.getBIP47PaymentCode(); + const [isLoading, setIsLoading] = useState(false); - if (currentTab === segmentControlValues[0]) { - return {address && renderReceiveDetails()}; - } else { - return ( - - {!qrValue && {loc.bip47.not_found}} - {qrValue && ( - <> - - - - - )} - - ); + const handleTabChange = useCallback(index => { + setIsLoading(true); + // Use requestAnimationFrame to prevent UI blocking (better than InteractionManager) + requestAnimationFrame(() => { + setCurrentTab(segmentControlValues[index]); + // Add a small delay to allow the UI to update (sadly needed hack) + setTimeout(() => { + setIsLoading(false); + }, 100); + }); + }, []); + + const renderTabContent = () => { + if (isLoading) { + return ; } + + return ( + + ); }; return ( @@ -492,16 +535,12 @@ const ReceiveDetails = () => { tab === currentTab)} - onChange={index => { - setCurrentTab(segmentControlValues[index]); - }} + onChange={handleTabChange} /> )} {showAddress && renderTabContent()} - {address !== undefined && showAddress && ( - - )} + {address !== undefined && showAddress && } {showConfirmedBalance ? renderConfirmedBalance() : null} {showPendingBalance ? renderPendingBalance() : null} {!showAddress && !showPendingBalance && !showConfirmedBalance ? : null}