Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/pages/guides/connect-wallet.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ export const Example = () => {
return (
<div>
{data.connectors.map((connector) => (
<button disabled={!connector.ready} key={connector.id} onClick={() => connect(connector)}>
<button
disabled={!connector.ready}
key={connector.id}
onClick={() => connect(connector)}
>
{connector.name}
{!connector.ready && ' (unsupported)'}
</button>
Expand Down
19 changes: 15 additions & 4 deletions packages/react/src/hooks/accounts/useBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Unit, defaultChains, defaultL2Chains, erc20ABI } from 'wagmi-private'
import { useContext } from '../../context'
import { useProvider } from '../providers'
import { useBlockNumber } from '../network-status'
import { useCacheBuster } from '../utils'
import { useCacheBuster, useCancel } from '../utils'

export type Config = {
/** Address or ENS name */
Expand Down Expand Up @@ -50,12 +50,18 @@ export const useBalance = ({
const [{ data: blockNumber }] = useBlockNumber({ skip: true, watch })
const [state, setState] = React.useState<State>(initialState)

const cancelQuery = useCancel()
const getBalance = React.useCallback(
async (config?: {
addressOrName: string
formatUnits?: Config['formatUnits']
token?: Config['token']
}) => {
let didCancel = false
cancelQuery(() => {
didCancel = true
})

try {
const config_ = config ?? {
addressOrName,
Expand Down Expand Up @@ -99,16 +105,21 @@ export const useBalance = ({
value,
}
}
setState((x) => ({ ...x, balance, loading: false }))

if (!didCancel) {
setState((x) => ({ ...x, balance, loading: false }))
}

return { data: balance, error: undefined }
} catch (error_) {
const error = <Error>error_
setState((x) => ({ ...x, error, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, error, loading: false }))
}
return { data: undefined, error }
}
},
[addressOrName, connector, formatUnits, provider, token],
[addressOrName, cancelQuery, connector, formatUnits, provider, token],
)

// Fetch balance when deps or chain changes
Expand Down
38 changes: 24 additions & 14 deletions packages/react/src/hooks/accounts/useConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from 'wagmi-private'

import { useContext } from '../../context'
import { useCancel } from '../utils'

type State = {
connector?: Connector
Expand All @@ -25,13 +26,19 @@ export const useConnect = () => {
} = useContext()
const [state, setState] = React.useState<State>(initialState)

const cancelQuery = useCancel()
const connect = React.useCallback(
async (
connector: Connector,
): Promise<{
data?: ConnectorData
error?: Error
}> => {
let didCancel = false
cancelQuery(() => {
didCancel = true
})

try {
const activeConnector = globalState?.connector
if (connector === activeConnector)
Expand All @@ -45,35 +52,38 @@ export const useConnect = () => {
}))
const data = await connector.connect()

// Update connector globally only after successful connection
setGlobalState((x) => ({ ...x, connector, data }))
setLastUsedConnector(connector.name)
setState((x) => ({ ...x, loading: false }))
if (!didCancel) {
// Update connector globally only after successful connection
setGlobalState((x) => ({ ...x, connector, data }))
setLastUsedConnector(connector.name)
setState((x) => ({ ...x, loading: false }))
}
return { data, error: undefined }
} catch (error_) {
const error = <Error>error_
setState((x) => ({ ...x, connector: undefined, error, loading: false }))
if (!didCancel) {
setState((x) => ({
...x,
connector: undefined,
error,
loading: false,
}))
}
return { data: undefined, error }
}
},
[globalState.connector, setGlobalState, setLastUsedConnector],
[cancelQuery, globalState.connector, setGlobalState, setLastUsedConnector],
)

// Keep connector in sync with global connector
React.useEffect(() => {
let didCancel = false
if (didCancel) return
Comment on lines -64 to -65
Copy link
Contributor Author

Choose a reason for hiding this comment

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

didCancel will always be false here, so the if (didCancel) is unnecessary.


setState((x) => ({
...x,
connector: globalState.connector,
error: undefined,
}))

return () => {
didCancel = true
}
Comment on lines -73 to -75
Copy link
Contributor Author

Choose a reason for hiding this comment

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

And this can be safely removed since the only use of didCancel here is in the if check right after its definition.

}, [globalState.connector])
return cancelQuery
}, [cancelQuery, globalState.connector])

return [
{
Expand Down
18 changes: 15 additions & 3 deletions packages/react/src/hooks/accounts/useNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react'
import { Chain, SwitchChainError, allChains } from 'wagmi-private'

import { useContext } from '../../context'
import { useCancel } from '../utils'

type State = {
error?: Error
Expand All @@ -25,22 +26,33 @@ export const useNetwork = () => {
(x) => x.id === chainId,
)

const cancelQuery = useCancel()
const switchNetwork = React.useCallback(
async (chainId: number) => {
let didCancel = false
cancelQuery(() => {
didCancel = true
})

if (!connector?.switchChain)
return { data: undefined, error: new SwitchChainError() }

try {
setState((x) => ({ ...x, error: undefined, loading: true }))
const chain = await connector.switchChain(chainId)
setState((x) => ({ ...x, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, loading: false }))
}
return { data: chain, error: undefined }
} catch (error_) {
const error = <Error>error_
setState((x) => ({ ...x, error, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, error, loading: false }))
}
return { data: undefined, error }
}
},
[connector],
[cancelQuery, connector],
)

return [
Expand Down
17 changes: 14 additions & 3 deletions packages/react/src/hooks/accounts/useSignMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Bytes } from 'ethers/lib/utils'
import { ConnectorNotFoundError, UserRejectedRequestError } from 'wagmi-private'

import { useContext } from '../../context'
import { useCancel } from '../utils'

export type Config = {
/** Message to sign with wallet */
Expand All @@ -25,8 +26,14 @@ export const useSignMessage = ({ message }: Config = {}) => {
} = useContext()
const [state, setState] = React.useState<State>(initialState)

const cancelQuery = useCancel()
const signMessage = React.useCallback(
async (config?: { message?: Config['message'] }) => {
let didCancel = false
cancelQuery(() => {
didCancel = true
})

try {
const config_ = config ?? { message }
if (!config_.message) throw new Error('message is required')
Expand All @@ -35,17 +42,21 @@ export const useSignMessage = ({ message }: Config = {}) => {
setState((x) => ({ ...x, error: undefined, loading: true }))
const signer = await connector.getSigner()
const signature = await signer.signMessage(config_.message)
setState((x) => ({ ...x, signature, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, signature, loading: false }))
}
return { data: signature, error: undefined }
} catch (error_) {
let error: Error = <Error>error_
if ((<ProviderRpcError>error_).code === 4001)
error = new UserRejectedRequestError()
setState((x) => ({ ...x, error, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, error, loading: false }))
}
return { data: undefined, error }
}
},
[connector, message],
[cancelQuery, connector, message],
)

return [
Expand Down
28 changes: 16 additions & 12 deletions packages/react/src/hooks/accounts/useSigner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react'
import { Signer } from 'ethers'

import { useContext } from '../../context'
import { useCacheBuster } from '../utils'
import { useCacheBuster, useCancel } from '../utils'

type Config = {
/** Disables fetching */
Expand All @@ -28,29 +28,33 @@ export const useSigner = ({ skip }: Config = {}) => {
} = useContext()
const [state, setState] = React.useState<State>(initialState)

const cancelQuery = useCancel()
const getSigner = React.useCallback(async () => {
let didCancel = false
cancelQuery(() => {
didCancel = true
})

try {
setState((x) => ({ ...x, error: undefined, loading: true }))
const signer = await connector?.getSigner()
setState((x) => ({ ...x, data: signer, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, data: signer, loading: false }))
}
return signer
} catch (error_) {
const error = <Error>error_
setState((x) => ({ ...x, data: undefined, error, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, data: undefined, error, loading: false }))
}
}
}, [connector])
}, [cancelQuery, connector])

React.useEffect(() => {
if (skip) return

let didCancel = false
if (didCancel) return
getSigner()

return () => {
didCancel = true
}
}, [cacheBuster, connector, getSigner, skip])
return cancelQuery
}, [cacheBuster, cancelQuery, getSigner, skip])

return [state, getSigner] as const
}
5 changes: 1 addition & 4 deletions packages/react/src/hooks/contracts/useContractEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export const useContractEvent = <
const listenerRef = React.useRef(listener)
listenerRef.current = listener

/* eslint-disable react-hooks/exhaustive-deps */
React.useEffect(() => {
const handler = (...event: Array<Parameters<Contract['on']>[1]>) =>
listenerRef.current(event)
Expand All @@ -40,8 +39,6 @@ export const useContractEvent = <

return () => {
contract_.off(eventName, handler)
return
}
}, [contract, eventName])
/* eslint-enable react-hooks/exhaustive-deps */
}, [contract, eventName, once])
}
43 changes: 24 additions & 19 deletions packages/react/src/hooks/contracts/useContractRead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import { Result } from 'ethers/lib/utils'
import { useBlockNumber } from '../network-status'
import { useProvider } from '../providers'
import { Config as UseContractConfig, useContract } from './useContract'
import { useCancel } from '../utils'

type Config = {
/** Arguments to pass contract method */
args?: any | any[]
overrides?: CallOverrides
/** Disables fetching */
skip?: boolean
/** Subscribe to changes */
watch?: boolean
}

Expand Down Expand Up @@ -38,11 +42,17 @@ export const useContractRead = <
const [{ data: blockNumber }] = useBlockNumber({ skip: true, watch })
const [state, setState] = React.useState<State>(initialState)

const cancelQuery = useCancel()
const read = React.useCallback(
async (config?: {
args?: Config['args']
overrides?: Config['overrides']
}) => {
let didCancel = false
cancelQuery(() => {
didCancel = true
})

try {
const config_ = config ?? { args, overrides }
const params = [
Expand All @@ -61,38 +71,33 @@ export const useContractRead = <
response: undefined,
}))
const response = (await contract[functionName](...params)) as Result
setState((x) => ({ ...x, loading: false, response }))
if (!didCancel) {
setState((x) => ({ ...x, loading: false, response }))
}
return { data: response, error: undefined }
} catch (error_) {
const error = <Error>error_
setState((x) => ({ ...x, error, loading: false }))
if (!didCancel) {
setState((x) => ({ ...x, error, loading: false }))
}
return { data: undefined, error }
}
},
[args, contract, functionName, overrides],
[args, cancelQuery, contract, functionName, overrides],
)

/* eslint-disable react-hooks/exhaustive-deps */
React.useEffect(() => {
if (skip) return

let didCancel = false
if (didCancel) return
read({ args, overrides })

return () => {
didCancel = true
}
}, [args, overrides, skip])
/* eslint-enable react-hooks/exhaustive-deps */
if (!skip) return
read()
return cancelQuery
}, [cancelQuery, read, skip])

/* eslint-disable react-hooks/exhaustive-deps */
React.useEffect(() => {
if (!watch) return
if (!blockNumber) return
read({ args, overrides })
}, [blockNumber])
/* eslint-enable react-hooks/exhaustive-deps */
read()
return cancelQuery
}, [blockNumber, cancelQuery, read, watch])

return [
{
Expand Down
Loading