Skip to content

Commit

Permalink
fix: useContractRead & useContractReads data instability (#659)
Browse files Browse the repository at this point in the history
* fix: useContractRead & useContractReads data instability

* pr review

* tests: update

* refactor: expose deepEqual from wagmi
  • Loading branch information
jxom committed Jul 5, 2022
1 parent b9f9c6d commit be76586
Show file tree
Hide file tree
Showing 28 changed files with 163 additions and 63 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-carrots-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'wagmi': patch
---

Added an `isDataEqual` config option to `useContractRead`, `useContractReads` & `useContractInfiniteReads` to define whether or not that data has changed. Defaults to `deepEqual`.
5 changes: 5 additions & 0 deletions .changeset/cool-coins-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'wagmi': patch
---

Added `onBlock` config to `useBlockNumber`
5 changes: 5 additions & 0 deletions .changeset/smart-lemons-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'wagmi': patch
---

Fixed an issue where `useContractRead` & `useContractReads` would return unstable data.
16 changes: 16 additions & 0 deletions docs/pages/docs/hooks/useBlockNumber.en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,22 @@ function App() {
}
```

### onBlock (optional)

Function to invoke when a new block is created.

```tsx {5-7}
import { useBlockNumber } from 'wagmi'

function App() {
const blockNumber = useBlockNumber({
onBlock(blockNumber) {
console.log('New block: ', blockNumber)
},
})
}
```

### onSuccess (optional)

Function to invoke when fetching new data is successful.
Expand Down
29 changes: 29 additions & 0 deletions docs/pages/docs/hooks/useContractInfiniteReads.en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,35 @@ function App() {
}
```

### isDataEqual (optional)

Determines if the data has changed or not. Defaults to `deepEqual`.

```tsx {20}
import { useContractInfiniteReads } from 'wagmi'

function App() {
const { data, isError, isLoading } = useContractInfiniteReads({
cacheKey: 'mlootAttributes',
contracts: (param = 0) => [
{
addressOrName: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
contractInterface: mlootABI,
functionName: 'getChest',
args: [param],
},
{
addressOrName: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
contractInterface: mlootABI,
functionName: 'getWaist',
args: [param],
},
],
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`.
Expand Down
17 changes: 17 additions & 0 deletions docs/pages/docs/hooks/useContractRead.en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,23 @@ function App() {
}
```

### isDataEqual (optional)

Determines if the data has changed or not. Defaults to `deepEqual`.

```tsx {11}
import { useContractRead } from 'wagmi'

function App() {
const contractRead = useContractRead({
addressOrName: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
contractInterface: wagmigotchiABI,
functionName: 'getHunger',
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`.
Expand Down
24 changes: 24 additions & 0 deletions docs/pages/docs/hooks/useContractReads.en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,30 @@ function App() {
}
```

### isDataEqual (optional)

Determines if the data has changed or not. Defaults to `deepEqual`.

```tsx {15}
import { useContractReads } from 'wagmi'

function App() {
const { data, isError, isLoading } = useContractReads({
contracts: [
{
...wagmigotchiContract,
functionName: 'getAlive',
},
{
...wagmigotchiContract,
functionName: 'getBoredom',
},
],
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`.
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/actions/contracts/multicall.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ describe('multicall', () => {
"hex": "0x05a6db",
"type": "BigNumber",
},
undefined,
null,
]
`)
})
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/actions/contracts/multicall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export async function multicall<Data extends any[] = Result[]>({
...params,
)) as AggregateResult
return results.map(({ returnData, success }, i) => {
if (!success) return undefined
if (!success) return null
const { addressOrName, contractInterface, functionName } = <
MulticallContract
>contracts[i]
Expand All @@ -103,7 +103,7 @@ export async function multicall<Data extends any[] = Result[]>({
})
if (!allowFailure) throw err
console.warn(err.message)
return undefined
return null
}

const contract = getContract({
Expand All @@ -118,7 +118,7 @@ export async function multicall<Data extends any[] = Result[]>({
return Array.isArray(result) && result.length === 1 ? result[0] : result
} catch (err) {
if (!allowFailure) throw err
return undefined
return null
}
}) as Data
}
2 changes: 1 addition & 1 deletion packages/core/src/actions/contracts/readContracts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ describe('readContracts', () => {
"hex": "0x05a6db",
"type": "BigNumber",
},
undefined,
null,
]
`)
})
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ it('should expose correct exports', () => {
"createStorage",
"noopStorage",
"configureChains",
"deepEqual",
"normalizeChainId",
]
`)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,5 @@ export type {
WebSocketProvider,
} from './types'

export { configureChains, normalizeChainId } from './utils'
export { configureChains, deepEqual, normalizeChainId } from './utils'
export type { ConfigureChainsConfig } from './utils'
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { configureChains } from './configureChains'
export type { ConfigureChainsConfig } from './configureChains'

export { deepEqual } from './deepEqual'
export { getInjectedName } from './getInjectedName'
export { normalizeChainId } from './normalizeChainId'
export { warn } from './warn'
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react'
import {
ReadContractResult,
ReadContractsConfig,
deepEqual,
readContracts,
} from '@wagmi/core'

Expand Down Expand Up @@ -77,6 +78,7 @@ export function useContractInfiniteReads<TPageParam = any>({
contracts,
enabled: enabled_ = true,
getNextPageParam,
isDataEqual = deepEqual,
keepPreviousData,
onError,
onSettled,
Expand All @@ -99,8 +101,9 @@ export function useContractInfiniteReads<TPageParam = any>({
return useInfiniteQuery(queryKey_, queryFn({ contracts }), {
cacheTime,
enabled,
keepPreviousData,
getNextPageParam,
isDataEqual,
keepPreviousData,
select,
staleTime,
suspense,
Expand Down
39 changes: 6 additions & 33 deletions packages/react/src/hooks/contracts/useContractRead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import * as React from 'react'
import {
ReadContractConfig,
ReadContractResult,
deepEqual,
readContract,
watchReadContract,
} from '@wagmi/core'
import { hashQueryKey, useQueryClient } from 'react-query'
import { hashQueryKey } from 'react-query'

import { QueryConfig, QueryFunctionArgs } from '../../types'
import { parseContractResult } from '../../utils'
import { useBlockNumber } from '../network-status'
import { useChainId, useQuery } from '../utils'
import { useChainId, useInvalidateOnBlock, useQuery } from '../utils'

type UseContractReadArgs = ReadContractConfig & {
/** If set to `true`, the cache will depend on the block number */
Expand Down Expand Up @@ -76,6 +76,7 @@ export function useContractRead({
cacheOnBlock = false,
cacheTime,
enabled: enabled_ = true,
isDataEqual = deepEqual,
select,
staleTime,
suspense,
Expand Down Expand Up @@ -121,40 +122,12 @@ export function useContractRead({
return enabled
}, [addressOrName, blockNumber, cacheOnBlock, enabled_, functionName])

const client = useQueryClient()
React.useEffect(() => {
if (enabled) {
const unwatch = watchReadContract(
{
addressOrName,
args,
chainId,
contractInterface,
functionName,
overrides,
listenToBlock: watch && !cacheOnBlock,
},
(result) => client.setQueryData(queryKey_, result),
)
return unwatch
}
}, [
addressOrName,
args,
cacheOnBlock,
chainId,
client,
contractInterface,
enabled,
functionName,
overrides,
queryKey_,
watch,
])
useInvalidateOnBlock({ enabled: watch && !cacheOnBlock, queryKey: queryKey_ })

return useQuery(queryKey_, queryFn, {
cacheTime,
enabled,
isDataEqual,
queryKeyHashFn,
select: (data) => {
const result = parseContractResult({
Expand Down
23 changes: 6 additions & 17 deletions packages/react/src/hooks/contracts/useContractReads.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import * as React from 'react'
import { hashQueryKey, useQueryClient } from 'react-query'
import { hashQueryKey } from 'react-query'
import {
ReadContractsConfig,
ReadContractsResult,
deepEqual,
readContracts,
watchReadContracts,
} from '@wagmi/core'

import { QueryConfig, QueryFunctionArgs } from '../../types'
import { useBlockNumber } from '../network-status'
import { useChainId, useQuery } from '../utils'
import { useChainId, useInvalidateOnBlock, useQuery } from '../utils'
import { parseContractResult } from '../../utils'

export type UseContractReadsConfig = QueryConfig<ReadContractsResult, Error> &
Expand Down Expand Up @@ -63,6 +63,7 @@ export function useContractReads({
contracts,
overrides,
enabled: enabled_ = true,
isDataEqual = deepEqual,
keepPreviousData,
onError,
onSettled,
Expand Down Expand Up @@ -93,24 +94,12 @@ export function useContractReads({
return enabled
}, [blockNumber, cacheOnBlock, contracts, enabled_])

const client = useQueryClient()
React.useEffect(() => {
if (enabled) {
const unwatch = watchReadContracts(
{
contracts,
overrides,
listenToBlock: watch && !cacheOnBlock,
},
(result) => client.setQueryData(queryKey_, result),
)
return unwatch
}
}, [cacheOnBlock, client, contracts, enabled, overrides, queryKey_, watch])
useInvalidateOnBlock({ enabled: watch && !cacheOnBlock, queryKey: queryKey_ })

return useQuery(queryKey_, queryFn, {
cacheTime,
enabled,
isDataEqual,
keepPreviousData,
queryKeyHashFn,
staleTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ describe('useBlockNumber', () => {
}
`)
})

it.todo('onBlock')
})

describe('return value', () => {
Expand Down

1 comment on commit be76586

@vercel
Copy link

@vercel vercel bot commented on be76586 Jul 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

wagmi – ./

wagmi-zoo.vercel.app
wagmi.sh
wagmi-git-main-zoo.vercel.app
www.wagmi.sh
wagmi-xyz.vercel.app

Please sign in to comment.