Pagination is not really a thing when it comes to the getProgramAcccount
RPC method. This tutorial demonstrates how you can still simulate NFT pagination by lazy loading NFTs and fetching their metadata on demand.
We will be using the findAllByOwner method in the Metaplex SDK which will give us the list of NFTs without their JSON metadata loaded. This is important because if we had to fetch hundreds of NFTs with their JSON metadata, it will take a lot of time and greatly impact the performance of the application.
In this tutorial, we are going to:
- Use the
findAllByOwner
method. - Store the list of lazy-loaded NFTs.
- Fetch the metadata of for each NFT in the current page.
Okay, let's get started! 🔥
Note that you can find all the code below in this pages/index.js
file.
-
Create a new Next.js app.
This example uses a new NextJS app with Metaplex which can be created by following the instructions listed in Getting Started with Metaplex and Next.js.
-
Fetch all NFTs of a given wallet without their JSON metadata.
Once the user fills in their wallet address and clicks the "Fetch" button, we call the following
fetchNFTs
function.const fetchNFTs = async () => { try { setLoading(true); setCurrentView(null); const list = await mx.nfts().findAllByOwner({ owner: new PublicKey(address)}); setNftList(list); setCurrentPage(1); } catch (e) { console.error(e); } };
This sets the
Loading
state to true, invalidates the current view and calls thefindAllByOwner
method of the Metaplex SDK with the wallet address as input.The returned data is then set to the
nftList
state and the current page is reset to the first page since we will be displaying a new list of NFTs. -
Load the JSON metadata of every NFT in the current page.
We then use a
useEffect
hook to load the NFTs of the current page whenevernftList
orcurrentPage
gets updated.For instance, when the user provides its wallet address, the
nftList
is updated andcurrentPage
is set to 1, which means theuseEffect
hook will be triggered.
useEffect(() => {
if (!nftList) {
return;
}
const execute = async () => {
const startIndex = (currentPage - 1) * perPage;
const endIndex = currentPage * perPage;
const nfts = await loadData(startIndex, endIndex);
setCurrentView(nfts);
setLoading(false);
};
execute();
}, [nftList, currentPage]);
This useEffect calls the loadData
function which goes through the NFTs falling in the index range of current page and loads the NFT metadata that isn't loaded yet.
const loadData = async (startIndex, endIndex) => {
const nftsToLoad = nftList.filter((_, index) => (index >= startIndex && index < endIndex))
const promises = nftsToLoad.map((metadata) => mx.nfts().load({ metadata }));
return Promise.all(promises);
};
The range of NFTs falling on the current page is then set to the currentView
state and displayed.
-
What happens when the page changes?
Whenever the user clicks the "Next Page" or "Prev Page" button, the
useEffect
hook is again triggered. That means, it will load the JSON metadata for any NFT within that index range that isn't already loaded and display them to the current view. -
That's it! 🎉
Congrats, you've now got a simple app that displays the NFTs inside a wallet. Let's see the final output!