From 7beb009c4a8e95af1c1114810cd480d7b90a6ec9 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Thu, 7 Apr 2022 12:05:16 +0800 Subject: [PATCH 1/4] fix: reduce token list rerenders --- .../shared/src/UI/components/ERC20TokenList/index.tsx | 3 ++- .../evm/hooks/useERC20TokensDetailedFromTokenLists.ts | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/UI/components/ERC20TokenList/index.tsx b/packages/shared/src/UI/components/ERC20TokenList/index.tsx index b02a1ebe0565..bef892556987 100644 --- a/packages/shared/src/UI/components/ERC20TokenList/index.tsx +++ b/packages/shared/src/UI/components/ERC20TokenList/index.tsx @@ -19,6 +19,7 @@ import { useNativeTokenDetailed, useTrustedERC20Tokens, } from '@masknet/web3-shared-evm' +import { EMPTY_LIST } from '@masknet/shared-base' import { MaskFixedSizeListProps, MaskTextFieldProps, SearchableList } from '@masknet/theme' import { Stack, Typography } from '@mui/material' import { useSharedI18N } from '../../../locales' @@ -64,7 +65,7 @@ export const ERC20TokenList = memo((props) => { } = props const { ERC20 } = useTokenListConstants(chainId) - const { value: erc20TokensDetailed = [], loading: erc20TokensDetailedLoading } = + const { value: erc20TokensDetailed = EMPTY_LIST, loading: erc20TokensDetailedLoading } = useERC20TokensDetailedFromTokenLists( ERC20, keyword, diff --git a/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts b/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts index f39867966928..1854bad183a0 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts @@ -7,18 +7,19 @@ import { useWeb3Context } from '../context' import { useChainId } from './useChainId' import { currySameAddress } from '../utils' import type { ERC20TokenDetailed, NativeTokenDetailed, ChainId } from '../types' +import { EMPTY_LIST } from '@masknet/shared-base' export function useERC20TokensDetailedFromTokenLists( lists?: string[], keyword = '', - additionalTokens: (ERC20TokenDetailed | NativeTokenDetailed)[] = [], + additionalTokens: (ERC20TokenDetailed | NativeTokenDetailed)[] = EMPTY_LIST, targetChainId?: ChainId, ): AsyncStateRetry<(ERC20TokenDetailed | NativeTokenDetailed)[]> { // #region fetch token lists const currentChainId = useChainId() const chainId = targetChainId ?? currentChainId const { fetchERC20TokensFromTokenLists } = useWeb3Context() - const { value: tokensFromList = [], ...asyncResult } = useAsyncRetry( + const { value: tokensFromList = EMPTY_LIST, ...asyncResult } = useAsyncRetry( async () => (!lists || lists.length === 0 ? [] : fetchERC20TokensFromTokenLists(lists, chainId)), [chainId, lists?.sort().join()], ) @@ -35,7 +36,7 @@ export function useERC20TokensDetailedFromTokenLists( { name: 'symbol', weight: 1 }, ], }), - [tokensFromList, additionalTokens], + [tokensFromList, additionalTokens.map((x) => x.address).join()], ) // #endregion @@ -45,10 +46,10 @@ export function useERC20TokensDetailedFromTokenLists( if (!keyword) return allToken return [ - ...(EthereumAddress.isValid(keyword) ? allToken.filter(currySameAddress(keyword)) : []), + ...(EthereumAddress.isValid(keyword) ? allToken.filter(currySameAddress(keyword)) : EMPTY_LIST), ...fuse.search(keyword).map((x) => x.item), ] - }, [keyword, fuse, tokensFromList, additionalTokens]) + }, [keyword, fuse, tokensFromList, additionalTokens.map((x) => x.address).join()]) // #endregion if (!asyncResult.error) From 18bcec160d7fdcd4916557407c5fb901d07943ba Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Thu, 7 Apr 2022 12:43:01 +0800 Subject: [PATCH 2/4] fix: render token list until it loaded everything --- .../ERC20TokenList/ERC20TokenListItem.tsx | 1 + .../UI/components/ERC20TokenList/index.tsx | 28 ++++++++++++------- packages/shared/src/locales/en-US.json | 2 +- .../SearchableList/SearchableList.tsx | 5 ++-- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/shared/src/UI/components/ERC20TokenList/ERC20TokenListItem.tsx b/packages/shared/src/UI/components/ERC20TokenList/ERC20TokenListItem.tsx index aa2a399871f9..77373a1f80e2 100644 --- a/packages/shared/src/UI/components/ERC20TokenList/ERC20TokenListItem.tsx +++ b/packages/shared/src/UI/components/ERC20TokenList/ERC20TokenListItem.tsx @@ -142,6 +142,7 @@ export const getERC20TokenListItem = return ( { targetChainId?: ChainId @@ -88,8 +88,9 @@ export const ERC20TokenList = memo((props) => { (!excludeTokens.length || !excludeTokens.some(currySameAddress(token.address))), ) - const renderTokens = uniqBy([...tokens, ...filteredTokens, ...(searchedToken ? [searchedToken] : [])], (x) => - x.address.toLowerCase(), + const renderTokens = uniqBy( + [...tokens, ...filteredTokens, ...(searchedToken ? [searchedToken] : EMPTY_LIST)], + (x) => x.address.toLowerCase(), ) const { @@ -102,17 +103,24 @@ export const ERC20TokenList = memo((props) => { chainId, ) - const renderAssets = - !account || !!assetsError || assetsLoading || searchedTokenLoading - ? [...renderTokens] - .sort(makeSortTokenFn(chainId, { isMaskBoost: true })) - .map((token) => ({ token: token, balance: null })) + const renderAssets = useMemo(() => { + return assetsLoading + ? EMPTY_LIST : keyword ? assets : [...assets].sort(makeSortAssertFn(chainId, { isMaskBoost: true })) + }, [ + chainId, + keyword, + assetsLoading, + assets + .map((x) => x.token.address) + .sort() + .join(), + ]) const getPlaceHolder = () => { - if (erc20TokensDetailedLoading) + if (erc20TokensDetailedLoading || assetsLoading) return if (searchedTokenLoading) return @@ -131,7 +139,7 @@ export const ERC20TokenList = memo((props) => { disableSearch={!!props.disableSearch} onSearch={setKeyword} data={renderAssets as Asset[]} - searchKey={['token.address', 'token.symbol', 'token.name']} + searchKey={SEARCH_KEYS} itemRender={getERC20TokenListItem( trustedERC20Tokens, searchedToken ? [searchedToken] : [], diff --git a/packages/shared/src/locales/en-US.json b/packages/shared/src/locales/en-US.json index 134f72c9fc51..c0aca43099c6 100644 --- a/packages/shared/src/locales/en-US.json +++ b/packages/shared/src/locales/en-US.json @@ -4,7 +4,7 @@ "balance": "Balance", "select_token": "Select a Token", "erc20_token_list_placeholder": "Token name or contract address", - "erc20_token_list_loading": "Loading token lists..", + "erc20_token_list_loading": "Loading token lists...", "erc20_search_token_loading": "Loading token...", "erc20_search_not_token_found": "No results or contract address does not meet the query criteria.", "address_viewer_binding_rules_title": "The NFT gallary will show NFTs as below rules:", diff --git a/packages/theme/src/Components/SearchableList/SearchableList.tsx b/packages/theme/src/Components/SearchableList/SearchableList.tsx index d78daa29ce29..269f3d6acc08 100644 --- a/packages/theme/src/Components/SearchableList/SearchableList.tsx +++ b/packages/theme/src/Components/SearchableList/SearchableList.tsx @@ -7,6 +7,7 @@ import { makeStyles } from '../../makeStyles' import { MaskSearchableItemInList } from './MaskSearchableItemInList' import { MaskTextField, MaskTextFieldProps } from '../TextField' import { SearchIcon } from '@masknet/icons' +import { EMPTY_LIST } from '@masknet/shared-base' export interface MaskSearchableListProps { /** The list data should be render */ @@ -48,7 +49,7 @@ export interface MaskSearchableListProps { * /> * ) */ -export function SearchableList({ +export function SearchableList({ itemKey, data, placeholder, @@ -72,7 +73,7 @@ export function SearchableList({ shouldSort: true, threshold: 0.45, minMatchCharLength: 1, - keys: searchKey ?? Object.keys(data.length > 0 ? data[0] : []), + keys: searchKey ?? Object.keys(data.length > 0 ? data[0] : EMPTY_LIST), }), [data, searchKey], ) From 05d29063db211b80359edd2ca688536afec5498c Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 11 Apr 2022 10:34:36 +0800 Subject: [PATCH 3/4] refactor: no need EMPTY_LIST --- .../theme/src/Components/SearchableList/SearchableList.tsx | 3 +-- .../evm/hooks/useERC20TokensDetailedFromTokenLists.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/theme/src/Components/SearchableList/SearchableList.tsx b/packages/theme/src/Components/SearchableList/SearchableList.tsx index 269f3d6acc08..120ef0bd4ba4 100644 --- a/packages/theme/src/Components/SearchableList/SearchableList.tsx +++ b/packages/theme/src/Components/SearchableList/SearchableList.tsx @@ -7,7 +7,6 @@ import { makeStyles } from '../../makeStyles' import { MaskSearchableItemInList } from './MaskSearchableItemInList' import { MaskTextField, MaskTextFieldProps } from '../TextField' import { SearchIcon } from '@masknet/icons' -import { EMPTY_LIST } from '@masknet/shared-base' export interface MaskSearchableListProps { /** The list data should be render */ @@ -73,7 +72,7 @@ export function SearchableList({ shouldSort: true, threshold: 0.45, minMatchCharLength: 1, - keys: searchKey ?? Object.keys(data.length > 0 ? data[0] : EMPTY_LIST), + keys: searchKey ?? Object.keys(data.length > 0 ? data[0] : []), }), [data, searchKey], ) diff --git a/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts b/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts index 1854bad183a0..e516049e2d39 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokensDetailedFromTokenLists.ts @@ -46,7 +46,7 @@ export function useERC20TokensDetailedFromTokenLists( if (!keyword) return allToken return [ - ...(EthereumAddress.isValid(keyword) ? allToken.filter(currySameAddress(keyword)) : EMPTY_LIST), + ...(EthereumAddress.isValid(keyword) ? allToken.filter(currySameAddress(keyword)) : []), ...fuse.search(keyword).map((x) => x.item), ] }, [keyword, fuse, tokensFromList, additionalTokens.map((x) => x.address).join()]) From 76beb8a6d835ffd91ec2ed3c27434ea4cd3e06a8 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 11 Apr 2022 10:41:29 +0800 Subject: [PATCH 4/4] refactor: code style --- packages/theme/src/Components/SearchableList/SearchableList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/theme/src/Components/SearchableList/SearchableList.tsx b/packages/theme/src/Components/SearchableList/SearchableList.tsx index 120ef0bd4ba4..eb3ed30c425a 100644 --- a/packages/theme/src/Components/SearchableList/SearchableList.tsx +++ b/packages/theme/src/Components/SearchableList/SearchableList.tsx @@ -72,7 +72,7 @@ export function SearchableList({ shouldSort: true, threshold: 0.45, minMatchCharLength: 1, - keys: searchKey ?? Object.keys(data.length > 0 ? data[0] : []), + keys: searchKey ?? data.length > 0 ? Object.keys(data[0]) : [], }), [data, searchKey], )