Commit babfebcc authored by lynn's avatar lynn Committed by GitHub

refactor: view my nfts loading optimization (#5318)

* working

* remove commented code
parent ea02d9e9
...@@ -12,7 +12,7 @@ import { useWalletBalance } from 'nft/hooks' ...@@ -12,7 +12,7 @@ import { useWalletBalance } from 'nft/hooks'
import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css' import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css'
import { OSCollectionsFetcher } from 'nft/queries' import { OSCollectionsFetcher } from 'nft/queries'
import { WalletCollection } from 'nft/types' import { WalletCollection } from 'nft/types'
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react' import { Dispatch, SetStateAction, Suspense, useEffect, useMemo, useState } from 'react'
import InfiniteScroll from 'react-infinite-scroll-component' import InfiniteScroll from 'react-infinite-scroll-component'
import { useInfiniteQuery } from 'react-query' import { useInfiniteQuery } from 'react-query'
import { easings, useSpring } from 'react-spring' import { easings, useSpring } from 'react-spring'
...@@ -21,6 +21,7 @@ import shallow from 'zustand/shallow' ...@@ -21,6 +21,7 @@ import shallow from 'zustand/shallow'
import { EmptyWalletContent } from './EmptyWalletContent' import { EmptyWalletContent } from './EmptyWalletContent'
import * as styles from './ProfilePage.css' import * as styles from './ProfilePage.css'
import { ProfileBodyLoadingSkeleton } from './ProfilePageLoadingSkeleton'
import { ViewMyNftsAsset } from './ViewMyNftsAsset' import { ViewMyNftsAsset } from './ViewMyNftsAsset'
const ProfilePageColumn = styled(Column)` const ProfilePageColumn = styled(Column)`
...@@ -49,9 +50,6 @@ const PADDING = 16 ...@@ -49,9 +50,6 @@ const PADDING = 16
export const ProfilePage = () => { export const ProfilePage = () => {
const { address } = useWalletBalance() const { address } = useWalletBalance()
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
const walletCollections = useWalletCollections((state) => state.walletCollections) const walletCollections = useWalletCollections((state) => state.walletCollections)
const setWalletCollections = useWalletCollections((state) => state.setWalletCollections) const setWalletCollections = useWalletCollections((state) => state.setWalletCollections)
const { resetSellAssets } = useSellAsset( const { resetSellAssets } = useSellAsset(
...@@ -61,11 +59,9 @@ export const ProfilePage = () => { ...@@ -61,11 +59,9 @@ export const ProfilePage = () => {
shallow shallow
) )
const sellAssets = useSellAsset((state) => state.sellAssets) const sellAssets = useSellAsset((state) => state.sellAssets)
const isBagExpanded = useBag((state) => state.bagExpanded)
const toggleBag = useBag((state) => state.toggleBag) const toggleBag = useBag((state) => state.toggleBag)
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded() const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
const isMobile = useIsMobile() const isMobile = useIsMobile()
const [currentTokenPlayingMedia, setCurrentTokenPlayingMedia] = useState<string | undefined>()
const getOwnerCollections = async ({ pageParam = 0 }) => { const getOwnerCollections = async ({ pageParam = 0 }) => {
const res = await OSCollectionsFetcher({ const res = await OSCollectionsFetcher({
...@@ -95,12 +91,6 @@ export const ProfilePage = () => { ...@@ -95,12 +91,6 @@ export const ProfilePage = () => {
refetchOnMount: false, refetchOnMount: false,
}) })
const {
walletAssets: ownerAssets,
loadNext,
hasNext,
} = useNftBalanceQuery(address, collectionFilters, [], DEFAULT_WALLET_ASSET_QUERY_AMOUNT)
const ownerCollections = useMemo( const ownerCollections = useMemo(
() => (isSuccess ? ownerCollectionsData?.pages.map((page) => page.data).flat() : null), () => (isSuccess ? ownerCollectionsData?.pages.map((page) => page.data).flat() : null),
[isSuccess, ownerCollectionsData] [isSuccess, ownerCollectionsData]
...@@ -110,89 +100,28 @@ export const ProfilePage = () => { ...@@ -110,89 +100,28 @@ export const ProfilePage = () => {
ownerCollections && setWalletCollections(ownerCollections) ownerCollections && setWalletCollections(ownerCollections)
}, [ownerCollections, setWalletCollections]) }, [ownerCollections, setWalletCollections])
const { gridX } = useSpring({
gridX: isFiltersExpanded ? FILTER_SIDEBAR_WIDTH : -PADDING,
config: {
duration: 250,
easing: easings.easeOutSine,
},
})
return ( return (
<ProfilePageColumn width="full" paddingTop={{ sm: `${PADDING}`, md: '40' }}> <ProfilePageColumn width="full" paddingTop={{ sm: `${PADDING}`, md: '40' }}>
{ownerAssets?.length === 0 ? ( <>
<EmptyWalletContent /> <ProfileHeader>My NFTs</ProfileHeader>
) : ( <Row alignItems="flex-start" position="relative">
<> <FilterSidebar
<ProfileHeader>My NFTs</ProfileHeader> fetchNextPage={fetchNextPage}
<Row alignItems="flex-start" position="relative"> hasNextPage={hasNextPage}
<FilterSidebar isFetchingNextPage={isFetchingNextPage}
fetchNextPage={fetchNextPage} walletCollections={walletCollections}
hasNextPage={hasNextPage} />
isFetchingNextPage={isFetchingNextPage} {(!isMobile || !isFiltersExpanded) && (
walletCollections={walletCollections} <Suspense fallback={<ProfileBodyLoadingSkeleton />}>
/> <ProfilePageNfts
walletCollections={walletCollections}
{(!isMobile || !isFiltersExpanded) && ( isFiltersExpanded={isFiltersExpanded}
<Column width="full"> setFiltersExpanded={setFiltersExpanded}
<AnimatedBox />
flexShrink="0" </Suspense>
position={isMobile && isBagExpanded ? 'fixed' : 'static'} )}
style={{ </Row>
transform: gridX.to( </>
(x) =>
`translate(${Number(x) - (!isMobile && isFiltersExpanded ? FILTER_SIDEBAR_WIDTH : -PADDING)}px)`
),
}}
paddingY="20"
>
<Row gap="8" flexWrap="nowrap" justifyContent="space-between">
<FilterButton
isMobile={isMobile}
isFiltersExpanded={isFiltersExpanded}
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
/>
</Row>
<Row>
<CollectionFiltersRow
collections={walletCollections}
collectionFilters={collectionFilters}
setCollectionFilters={setCollectionFilters}
clearCollectionFilters={clearCollectionFilters}
/>
</Row>
<InfiniteScroll
next={() => loadNext(DEFAULT_WALLET_ASSET_QUERY_AMOUNT)}
hasMore={hasNext}
loader={
<Center>
<LoadingSparkle />
</Center>
}
dataLength={ownerAssets?.length ?? 0}
style={{ overflow: 'unset' }}
>
<div className={assetList}>
{ownerAssets?.length
? ownerAssets.map((asset, index) => (
<div key={index}>
<ViewMyNftsAsset
asset={asset}
mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
hideDetails={sellAssets.length > 0}
/>
</div>
))
: null}
</div>
</InfiniteScroll>
</AnimatedBox>
</Column>
)}
</Row>
</>
)}
{sellAssets.length > 0 && ( {sellAssets.length > 0 && (
<Row <Row
display={{ sm: 'flex', md: 'none' }} display={{ sm: 'flex', md: 'none' }}
...@@ -243,6 +172,100 @@ export const ProfilePage = () => { ...@@ -243,6 +172,100 @@ export const ProfilePage = () => {
) )
} }
const ProfilePageNfts = ({
walletCollections,
isFiltersExpanded,
setFiltersExpanded,
}: {
walletCollections: WalletCollection[]
isFiltersExpanded: boolean
setFiltersExpanded: (filtersExpanded: boolean) => void
}) => {
const { address } = useWalletBalance()
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
const isBagExpanded = useBag((state) => state.bagExpanded)
const [currentTokenPlayingMedia, setCurrentTokenPlayingMedia] = useState<string | undefined>()
const isMobile = useIsMobile()
const sellAssets = useSellAsset((state) => state.sellAssets)
const {
walletAssets: ownerAssets,
loadNext,
hasNext,
} = useNftBalanceQuery(address, collectionFilters, [], DEFAULT_WALLET_ASSET_QUERY_AMOUNT)
const { gridX } = useSpring({
gridX: isFiltersExpanded ? FILTER_SIDEBAR_WIDTH : -PADDING,
config: {
duration: 250,
easing: easings.easeOutSine,
},
})
return (
<Column width="full">
{ownerAssets?.length === 0 ? (
<EmptyWalletContent />
) : (
<AnimatedBox
flexShrink="0"
position={isMobile && isBagExpanded ? 'fixed' : 'static'}
style={{
transform: gridX.to(
(x) => `translate(${Number(x) - (!isMobile && isFiltersExpanded ? FILTER_SIDEBAR_WIDTH : -PADDING)}px)`
),
}}
paddingY="20"
>
<Row gap="8" flexWrap="nowrap" justifyContent="space-between">
<FilterButton
isMobile={isMobile}
isFiltersExpanded={isFiltersExpanded}
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
/>
</Row>
<Row>
<CollectionFiltersRow
collections={walletCollections}
collectionFilters={collectionFilters}
setCollectionFilters={setCollectionFilters}
clearCollectionFilters={clearCollectionFilters}
/>
</Row>
<InfiniteScroll
next={() => loadNext(DEFAULT_WALLET_ASSET_QUERY_AMOUNT)}
hasMore={hasNext}
loader={
<Center>
<LoadingSparkle />
</Center>
}
dataLength={ownerAssets?.length ?? 0}
style={{ overflow: 'unset' }}
>
<div className={assetList}>
{ownerAssets?.length
? ownerAssets.map((asset, index) => (
<div key={index}>
<ViewMyNftsAsset
asset={asset}
mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
hideDetails={sellAssets.length > 0}
/>
</div>
))
: null}
</div>
</InfiniteScroll>
</AnimatedBox>
)}
</Column>
)
}
const CollectionFiltersRow = ({ const CollectionFiltersRow = ({
collections, collections,
collectionFilters, collectionFilters,
......
import { Box } from 'nft/components/Box'
import { assetList } from 'nft/components/collection/CollectionNfts.css' import { assetList } from 'nft/components/collection/CollectionNfts.css'
import { loadingAsset } from 'nft/css/loading.css'
import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css' import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
...@@ -35,7 +37,6 @@ const AccountDetailsSkeletonWrapper = styled(SkeletonRowWrapper)` ...@@ -35,7 +37,6 @@ const AccountDetailsSkeletonWrapper = styled(SkeletonRowWrapper)`
const ProfileDetailsSkeleton = styled.div` const ProfileDetailsSkeleton = styled.div`
width: 180px; width: 180px;
height: 36px; height: 36px;
background: ${({ theme }) => theme.backgroundModule};
border-radius: 12px; border-radius: 12px;
` `
...@@ -46,39 +47,42 @@ const FilterBarSkeletonWrapper = styled(SkeletonRowWrapper)` ...@@ -46,39 +47,42 @@ const FilterBarSkeletonWrapper = styled(SkeletonRowWrapper)`
const FilterButtonSkeleton = styled.div` const FilterButtonSkeleton = styled.div`
width: 92px; width: 92px;
height: 44px; height: 44px;
background: ${({ theme }) => theme.backgroundModule};
border-radius: 12px; border-radius: 12px;
` `
const SellButtonSkeleton = styled.div` const SellButtonSkeleton = styled.div`
width: 80px; width: 80px;
height: 44px; height: 44px;
background: ${({ theme }) => theme.backgroundModule};
border-radius: 12px; border-radius: 12px;
` `
export const ProfileAssetCardSkeleton = styled.div` export const ProfileAssetCardSkeleton = styled.div`
width: 100%; width: 100%;
height: 330px; height: 330px;
background: ${({ theme }) => theme.backgroundModule};
border-radius: 20px; border-radius: 20px;
` `
export const ProfileAssetCardDisplaySectionSkeleton = () => {
return (
<Box width="full" className={assetList}>
{Array.from(Array(DEFAULT_WALLET_ASSET_QUERY_AMOUNT), (_, index) => (
<ProfileAssetCardSkeleton key={index} className={loadingAsset} />
))}
</Box>
)
}
export const ProfileBodyLoadingSkeleton = () => { export const ProfileBodyLoadingSkeleton = () => {
return ( return (
<SkeletonBodyWrapper> <SkeletonBodyWrapper>
<AccountDetailsSkeletonWrapper> <AccountDetailsSkeletonWrapper>
<ProfileDetailsSkeleton /> <ProfileDetailsSkeleton className={loadingAsset} />
</AccountDetailsSkeletonWrapper> </AccountDetailsSkeletonWrapper>
<FilterBarSkeletonWrapper> <FilterBarSkeletonWrapper>
<FilterButtonSkeleton /> <FilterButtonSkeleton className={loadingAsset} />
<SellButtonSkeleton /> <SellButtonSkeleton className={loadingAsset} />
</FilterBarSkeletonWrapper> </FilterBarSkeletonWrapper>
<div className={assetList}> <ProfileAssetCardDisplaySectionSkeleton />
{Array.from(Array(DEFAULT_WALLET_ASSET_QUERY_AMOUNT), (_, index) => (
<ProfileAssetCardSkeleton key={index} />
))}
</div>
</SkeletonBodyWrapper> </SkeletonBodyWrapper>
) )
} }
......
import { Trace } from '@uniswap/analytics' import { Trace } from '@uniswap/analytics'
import { PageName } from '@uniswap/analytics-events' import { PageName } from '@uniswap/analytics-events'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { useLoadNftBalanceQuery } from 'graphql/data/nft/NftBalance'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { Center, Column } from 'nft/components/Flex' import { Center, Column } from 'nft/components/Flex'
import { ListPage } from 'nft/components/profile/list/ListPage' import { ListPage } from 'nft/components/profile/list/ListPage'
...@@ -50,7 +49,7 @@ const ProfileContent = () => { ...@@ -50,7 +49,7 @@ const ProfileContent = () => {
{/* <Head> TODO: figure out metadata tagging {/* <Head> TODO: figure out metadata tagging
<title>Genie | Sell</title> <title>Genie | Sell</title>
</Head> */} </Head> */}
{account != null ? ( {!!account ? (
<Box style={{ width: `calc(100% - ${cartExpanded ? SHOPPING_BAG_WIDTH : 0}px)` }}> <Box style={{ width: `calc(100% - ${cartExpanded ? SHOPPING_BAG_WIDTH : 0}px)` }}>
{sellPageState === ProfilePageStateType.VIEWING ? <ProfilePage /> : <ListPage />} {sellPageState === ProfilePageStateType.VIEWING ? <ProfilePage /> : <ListPage />}
</Box> </Box>
...@@ -74,9 +73,6 @@ const ProfileContent = () => { ...@@ -74,9 +73,6 @@ const ProfileContent = () => {
} }
const Profile = () => { const Profile = () => {
const { account } = useWeb3React()
useLoadNftBalanceQuery(account, [])
return ( return (
<Suspense fallback={<ProfilePageLoadingSkeleton />}> <Suspense fallback={<ProfilePageLoadingSkeleton />}>
<ProfileContent /> <ProfileContent />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment