From 3ab52962d5d2fbc2794826142b0f1e01f4c5b071 Mon Sep 17 00:00:00 2001 From: Nikita Date: Mon, 4 Nov 2024 13:09:41 +0400 Subject: [PATCH] perf(asset-selector): do not render all assets at once --- src/constants/common.ts | 1 + src/popup/components/Modal.vue | 21 ++++- src/popup/components/Modals/AssetSelector.vue | 76 +++++++------------ tests/e2e/support/commands.js | 2 - 4 files changed, 47 insertions(+), 53 deletions(-) diff --git a/src/constants/common.ts b/src/constants/common.ts index 964ceaa56..18f6b0a36 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -83,6 +83,7 @@ export const NETWORK_NAME_MAX_LENGTH = 15; export const DEFAULT_WAITING_HEIGHT = 15; export const FIXED_TABS_SCROLL_HEIGHT = 30; +export const ASSETS_PER_PAGE = 30; export const TXS_PER_PAGE = 30; export const AUTO_EXTEND_NAME_BLOCKS_INTERVAL = 17000; diff --git a/src/popup/components/Modal.vue b/src/popup/components/Modal.vue index b59579b06..0fbd9d7ad 100644 --- a/src/popup/components/Modal.vue +++ b/src/popup/components/Modal.vue @@ -21,7 +21,10 @@ 'min-height': minHeight, }" > -
+
(); + + const { setScrollConf } = useScrollConfig(); + const { initViewport } = useViewport(); + const showHeader = computed(() => props.hasCloseButton || props.header || slots.header); function handleClose() { @@ -128,6 +139,10 @@ export default defineComponent({ } onMounted(() => { + if (props.initializeViewport) { + setScrollConf(false); + initViewport(scrollElem.value!); + } document.addEventListener('ionBackButton', onBackButtonHandler); if (!document.body.style.overflow) { document.body.style.overflow = 'hidden'; @@ -135,6 +150,9 @@ export default defineComponent({ }); onBeforeUnmount(() => { + if (props.initializeViewport) { + setScrollConf(false); + } document.removeEventListener('ionBackButton', onBackButtonHandler); document.body.style.overflow = ''; }); @@ -143,6 +161,7 @@ export default defineComponent({ handleClose, IS_FIREFOX, IS_EXTENSION, + scrollElem, showHeader, }; }, diff --git a/src/popup/components/Modals/AssetSelector.vue b/src/popup/components/Modals/AssetSelector.vue index 440226c5a..15285ce27 100644 --- a/src/popup/components/Modals/AssetSelector.vue +++ b/src/popup/components/Modals/AssetSelector.vue @@ -3,10 +3,10 @@ full-screen from-bottom has-close-button + initialize-viewport no-padding class="asset-selector" @close="reject()" - @open="onModalOpen" > - -
-
+ @@ -45,9 +41,9 @@ import { computed, defineComponent, - nextTick, PropType, ref, + watch, } from 'vue'; import type { IAsset, @@ -56,11 +52,12 @@ import type { ResolveCallback, } from '@/types'; import { useAccountAssetsList } from '@/composables'; +import { ASSETS_PER_PAGE } from '@/constants'; import Modal from '../Modal.vue'; import AssetListItem from '../Assets/AssetListItem.vue'; import InputSearch from '../InputSearch.vue'; -import Loader from '../Loader.vue'; +import InfiniteScroll from '../InfiniteScroll.vue'; export type AssetSelectorResolvedVal = IAsset; @@ -70,7 +67,7 @@ export default defineComponent({ AssetListItem, Modal, InputSearch, - Loader, + InfiniteScroll, }, props: { resolve: { @@ -83,52 +80,44 @@ export default defineComponent({ withBalanceOnly: Boolean, }, setup(props) { - const loading = ref(true); const searchTerm = ref(''); const isFullyOpen = ref(false); + const pageNumber = ref(1); const { accountAssetsFiltered } = useAccountAssetsList({ searchTerm, withBalanceOnly: props.withBalanceOnly, }); - const accountAssetsToDisplay = computed(() => (props.protocol) - ? accountAssetsFiltered.value.filter(({ protocol }) => protocol === props.protocol) - : accountAssetsFiltered.value); + const accountAssetsToDisplay = computed(() => ( + (props.protocol) + ? accountAssetsFiltered.value.filter(({ protocol }) => protocol === props.protocol) + : accountAssetsFiltered.value + ) + .slice(0, pageNumber.value * ASSETS_PER_PAGE)); function isAssetSelected(token: IAsset): boolean { return !!props.selectedToken && props.selectedToken.contractId === token.contractId; } - - /** - * Delay displaying tokens list until the modal transition is finished to prevent - * performance issues when both animating the modal and rendering large amount of data. - */ - async function onModalOpen() { - await nextTick(); - isFullyOpen.value = true; - setTimeout(() => { - loading.value = false; - }, 250); - } + watch( + searchTerm, + () => { + pageNumber.value = 1; + }, + ); return { - loading, - searchTerm, - isFullyOpen, accountAssetsToDisplay, + isFullyOpen, + pageNumber, + searchTerm, isAssetSelected, - onModalOpen, }; }, }); diff --git a/tests/e2e/support/commands.js b/tests/e2e/support/commands.js index bbd2368ca..a036bfcbd 100644 --- a/tests/e2e/support/commands.js +++ b/tests/e2e/support/commands.js @@ -323,8 +323,6 @@ Cypress.Commands.add('generateReceiveLinkAndVisit', (address, amount, token = nu if (token) { cy.get('[data-cy=select-asset]') .click() - .get('[data-cy=loader]') - .should('be.visible') .get('.modal .header [data-cy=input]') .type(token.contractId) .get('.tokens-list-item:first-child', { timeout: 8000 })