• React
  • Hooks
  • useContractInfiniteReads

useContractInfiniteReads

Hook for calling multiple ethers Contract read-only methods with "infinite scrolling" ("fetch more") support. Useful for rendering a dynamic list of contract data.

import { useContractInfiniteReads } from 'wagmi'

Usage

The following example uses the more loot contract.

The useContractInfiniteReads hook requires:

  • cacheKey: unique key to store the data in the cache
  • contracts: a function that provides a param (derived from getNextPageParam or fetchNextPage) as an argument and expects to return an array of contracts. In the example below, param is the token ID.
import { BigNumber } from 'ethers'
import { useContractInfiniteReads } from 'wagmi'
import mlootABI from './mlootABI.json'
 
const mlootContractConfig = {
  address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
  abi: mlootABI,
}
 
function App() {
  const { data, fetchNextPage } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        { ...mlootContractConfig, functionName: 'getChest', args },
        { ...mlootContractConfig, functionName: 'getFoot', args },
        { ...mlootContractConfig, functionName: 'getHand', args },
      ],
    },
  })
}

You can also optionally provide getNextPageParam which will derive the param provided to contracts. In the example below, we want the param to increment by 1.

function App() {
  const { data, fetchNextPage } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        { ...mlootContractConfig, functionName: 'getChest', args },
        { ...mlootContractConfig, functionName: 'getFoot', args },
        { ...mlootContractConfig, functionName: 'getHand', args },
      ],
    },
    getNextPageParam: (_, pages) => pages.length + 1,
  })
}

Paginated indexes

Import the paginatedIndexesConfig helper to assist with paginated indexes. Useful for infinite pagination of token IDs.

In the example below, we are fetching 10 tokenURIs at a time from the more loot contract.

import { BigNumber } from 'ethers'
import { useContractInfiniteReads, paginatedIndexesConfig } from 'wagmi'
import mlootABI from './mlootABI.json'
 
const mlootContractConfig = {
  address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
  abi: mlootABI,
}
 
function App() {
  const { data, fetchNextPage } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    ...paginatedIndexesConfig(
      (index) => {
        return [
          {
            ...mlootContractConfig,
            functionName: 'tokenURI',
            args: [BigNumber.from(index)] as const,
          },
        ]
      },
      { start: 0, perPage: 10, direction: 'increment' },
    ),
  })
}

Return Value

{
  data: {
    pages: Result[][]
    pageParam: PageParam
  }
  error?: Error
  fetchNextPage: (options?: FetchNextPageOptions) => Promise<Result[]>
  hasNextPage: boolean
  isIdle: boolean
  isLoading: boolean
  isFetching: boolean
  isFetchingNextPage: boolean;
  isSuccess: boolean
  isError: boolean
  isFetched: boolean
  isFetchedAfterMount: boolean
  isRefetching: boolean
  refetch: (options: {
    throwOnError: boolean
    cancelRefetch: boolean
  }) => Promise<Result>
  status: 'idle' | 'error' | 'loading' | 'success'
}

Configuration

cacheKey

Unique key used to store the data in the cache.

import { useContractInfiniteReads } from 'wagmi'
 
function App() {
  const { data, fetchNextPage } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        { ...mlootContractConfig, functionName: 'getChest', args },
        { ...mlootContractConfig, functionName: 'getFoot', args },
        { ...mlootContractConfig, functionName: 'getHand', args },
      ],
    },
  })
}

contracts

address

Contract address.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
  })
}

abi

Contract ABI.

By defining inline or adding a const assertion to abi, TypeScript will infer the correct types for functionName, args, and hook result. See the wagmi TypeScript docs for more information.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
  })
}

functionName

Name of function to call.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
  })
}

args

Arguments to pass to function call.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
  })
}

chainId

Force a specific chain id for the request. The wagmi Client's ethers provider must be set up as a chain-aware function for this to work correctly.

import { useContractReads, chain } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
          chainId: chain.mainnet.id,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
          chainId: chain.mainnet.id,
        },
      ]
    },
  })
}

getNextPageParam (optional)

Derives the param provided to contracts. Provides the last page of the infinite list and an array of pages.

If there is no next page available, return undefined.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    getNextPageParam: (lastPage, allPages) =>
      !lastPage ? allPages.length + 1 : undefined,
  })
}

allowFailure (optional)

If a contract read fails while fetching, it will fail silently and not throw an error.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    allowFailure: false,
  })
}

overrides (optional)

Overrides to pass to function call.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    overrides: { from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e' },
  })
}

cacheTime (optional)

Time (in ms) which the data should remain in the cache. Defaults to 0.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    cacheTime: 2_000,
  })
}

enabled (optional)

Set this to false to disable this query from automatically running. Defaults to true.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    enabled: false,
  })
}

isDataEqual (deprecated, optional)

Use structuralSharing instead.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    isDataEqual: (prev, next) => prev === next,
  })
}

staleTime (optional)

Time (in ms) after data is considered stale. If set to Infinity the data will never be considered stale. Defaults to 0.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    staleTime: 2_000,
  })
}

select (optional)

Transform or select a part of the data returned by the contract.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    select: (data) => transform(data),
  })
}

structuralSharing (optional)

Keep referential identity of data and prevent rerenders. Defaults to (oldData, newData) => deepEqual(oldData, newData) ? oldData : replaceEqualDeep(oldData, newData). If set to false, structural sharing between query results will be disabled.

If set to a function, the old and new data values will be passed through this function, which should combine them into resolved data for the query. This way, you can retain references from the old data to improve performance even when that data contains non-serializable values.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    structuralSharing: (prev, next) => (prev === next ? prev : next),
  })
}

suspense (optional)

Set this to true to enable suspense mode.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    suspense: true,
  })
}

onSuccess (optional)

Function to invoke when fetching new data is successful.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    onSuccess(data) {
      console.log('Success', data)
    },
  })
}

onError (optional)

Function to invoke when an error is thrown while fetching new data.

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    onError(error) {
      console.log('error', error)
    },
  })
}

onSettled (optional)

Function to invoke when fetching is settled (either successfully fetched, or an error has thrown).

import { useContractInfiniteReads } from 'wagmi'
import { BigNumber } from 'ethers'
 
function App() {
  const { data, isError, isLoading } = useContractInfiniteReads({
    cacheKey: 'mlootAttributes',
    contracts(param = 0) {
      const args = [BigNumber.from(param)] as const
      return [
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getChest',
          args,
        },
        {
          address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
          abi: mlootABI,
          functionName: 'getWaist',
          args,
        },
      ]
    },
    onSettled(data) {
      console.log('Settled', data)
    },
  })
}