1
- import { useEffect , useState , useCallback , useMemo } from 'react'
1
+ import { useState , useCallback } from 'react'
2
+ import { useSyncExternalStore } from 'use-sync-external-store/shim'
2
3
3
4
import Web3Onboard from '@web3-onboard/core'
4
5
import type {
@@ -9,8 +10,8 @@ import type {
9
10
WalletState ,
10
11
ConnectedChain
11
12
} from '@web3-onboard/core'
12
-
13
- import { Chain } from '@web3-onboard/common '
13
+ import type { Chain } from '@web3-onboard/common'
14
+ import type { AppState } from '@web3-onboard/core/dist/types '
14
15
15
16
export let web3Onboard : OnboardAPI | null = null
16
17
@@ -19,43 +20,62 @@ export const init = (options: InitOptions): OnboardAPI => {
19
20
return web3Onboard
20
21
}
21
22
23
+ const HOOK_ERROR_MESSAGE = 'Must initialize before using hooks.'
24
+
25
+ const useAppState : {
26
+ ( ) : AppState
27
+ < K extends keyof AppState > ( stateKey ?: K ) : AppState [ K ]
28
+ } = ( stateKey = undefined ) => {
29
+ if ( ! web3Onboard ) throw new Error ( HOOK_ERROR_MESSAGE )
30
+
31
+ const { select , get } = web3Onboard . state
32
+
33
+ const subscribe = useCallback (
34
+ ( onStoreChange : ( ) => void ) => {
35
+ const { unsubscribe } = stateKey
36
+ ? select ( stateKey ) . subscribe ( onStoreChange )
37
+ : select ( ) . subscribe ( onStoreChange )
38
+
39
+ return ( ) => unsubscribe
40
+ } ,
41
+ [ stateKey ]
42
+ )
43
+
44
+ const getSnapshot = useCallback ( ( ) => {
45
+ const snapshot = get ( )
46
+ return stateKey ? snapshot [ stateKey ] : snapshot
47
+ } , [ stateKey ] )
48
+
49
+ return useSyncExternalStore ( subscribe , getSnapshot )
50
+ }
51
+
22
52
export const useConnectWallet = ( ) : [
23
53
{ wallet : WalletState | null ; connecting : boolean } ,
24
- ( options : ConnectOptions ) => Promise < void > ,
54
+ ( options ? : ConnectOptions ) => Promise < void > ,
25
55
( wallet : DisconnectOptions ) => Promise < void >
26
56
] => {
27
- if ( ! web3Onboard ) throw new Error ( 'Must initialize before using hooks.' )
57
+ if ( ! web3Onboard ) throw new Error ( HOOK_ERROR_MESSAGE )
28
58
29
- const [ wallet , setConnectedWallet ] = useState < WalletState | null > (
30
- ( ) => ( web3Onboard as OnboardAPI ) . state . get ( ) . wallets [ 0 ] || null
31
- )
32
- const [ connecting , setConnecting ] = useState ( false )
59
+ const { connectWallet , disconnectWallet } = web3Onboard
33
60
34
- useEffect ( ( ) => {
35
- const subscription = ( web3Onboard as OnboardAPI ) . state
36
- . select ( 'wallets' )
37
- . subscribe ( wallets => setConnectedWallet ( wallets [ 0 ] || null ) )
61
+ const wallets = useAppState ( 'wallets' )
62
+ const wallet = wallets [ 0 ] || null
38
63
39
- return ( ) => subscription . unsubscribe ( )
40
- } , [ wallet ] )
64
+ const [ connecting , setConnecting ] = useState < boolean > ( false )
41
65
42
- const connect = useCallback ( async ( options : ConnectOptions ) => {
66
+ const connect = useCallback ( async ( options ? : ConnectOptions ) => {
43
67
setConnecting ( true )
44
68
45
- const [ connectedWallet ] = await ( web3Onboard as OnboardAPI ) . connectWallet (
46
- options
47
- )
69
+ await connectWallet ( options )
48
70
49
71
setConnecting ( false )
50
- setConnectedWallet ( connectedWallet || null )
51
72
} , [ ] )
52
73
53
- const disconnect = useCallback ( async ( { label } ) => {
74
+ const disconnect = useCallback ( async ( { label } : DisconnectOptions ) => {
54
75
setConnecting ( true )
55
76
56
- await ( web3Onboard as OnboardAPI ) . disconnectWallet ( { label } )
77
+ await disconnectWallet ( { label } )
57
78
58
- setConnectedWallet ( null )
59
79
setConnecting ( false )
60
80
} , [ ] )
61
81
@@ -77,63 +97,35 @@ export const useSetChain = (
77
97
} ,
78
98
( options : SetChainOptions ) => Promise < boolean >
79
99
] => {
80
- if ( ! web3Onboard ) throw new Error ( 'Must initialize before using hooks.' )
100
+ if ( ! web3Onboard ) throw new Error ( HOOK_ERROR_MESSAGE )
81
101
82
- const { state, setChain } = web3Onboard as OnboardAPI
83
- const [ settingChain , setInProgress ] = useState < boolean > ( false )
84
-
85
- const [ connectedChain , setConnectedChain ] = useState < ConnectedChain | null > (
86
- ( ) => {
87
- const initialWallets = ( web3Onboard as OnboardAPI ) . state . get ( ) . wallets
88
- if ( initialWallets . length === 0 ) return null
89
- return (
90
- (
91
- initialWallets . find ( ( { label } ) => label === walletLabel ) ||
92
- initialWallets [ 0 ]
93
- ) . chains [ 0 ] || null
94
- )
95
- }
96
- )
102
+ const { setChain } = web3Onboard
97
103
98
- const chains = useMemo ( ( ) => state . get ( ) . chains , [ ] )
104
+ const { wallets , chains } = useAppState ( )
99
105
100
- useEffect ( ( ) => {
101
- const subscription = state . select ( 'wallets' ) . subscribe ( wallets => {
102
- const wallet =
103
- wallets . find ( ( { label } ) => label === walletLabel ) || wallets [ 0 ]
106
+ const connectedChain =
107
+ ( walletLabel
108
+ ? wallets . find ( ( { label } ) => label === walletLabel )
109
+ : wallets [ 0 ]
110
+ ) ?. chains [ 0 ] || null
104
111
105
- wallet && setConnectedChain ( wallet . chains [ 0 ] )
106
- } )
107
-
108
- return ( ) => subscription . unsubscribe ( )
109
- } , [ ] )
112
+ const [ settingChain , setInProgress ] = useState < boolean > ( false )
110
113
111
- const set = useCallback ( async ( options : SetChainOptions ) : Promise < boolean > => {
114
+ const set = useCallback ( async ( options : SetChainOptions ) => {
112
115
setInProgress ( true )
113
116
114
117
const success = await setChain ( { ...options , wallet : walletLabel } )
115
118
116
119
setInProgress ( false )
117
120
118
- return success ;
121
+ return success
119
122
} , [ ] )
120
123
121
124
return [ { chains, connectedChain, settingChain } , set ]
122
125
}
123
126
124
127
export const useWallets = ( ) : WalletState [ ] => {
125
- if ( ! web3Onboard ) throw new Error ( 'Must initialize before using hooks.' )
126
-
127
- const [ wallets , setConnectedWallets ] = useState < WalletState [ ] > (
128
- ( ) => ( web3Onboard as OnboardAPI ) . state . get ( ) . wallets
129
- )
130
-
131
- useEffect ( ( ) => {
132
- const wallets$ = ( web3Onboard as OnboardAPI ) . state . select ( 'wallets' )
133
- const subscription = wallets$ . subscribe ( setConnectedWallets )
134
-
135
- return ( ) => subscription . unsubscribe ( )
136
- } , [ ] )
128
+ if ( ! web3Onboard ) throw new Error ( HOOK_ERROR_MESSAGE )
137
129
138
- return wallets
130
+ return useAppState ( ' wallets' )
139
131
}
0 commit comments