Wagmi v2が来たぞ
前置き
個人的に好きなライブラリであるwagmiのv2が先日正式リリースされました!
ドキュメントを読んだり実際に動かしたりして気になった内容をピックアップして書いていきたいと思います。
※今回はReact向けライブラリについてのみです
v1からのMigrate手順全体は以下です。
また、基本的に以下のドキュメントをベースに記載しています。
Wagmiとは?
ウォレットとの接続や署名、トランザクションの送信などを簡単に行えるようにしてくれるdapp開発者向けのOSSライブラリです。
開発者体験(型安全)、パフォーマンス、機能の充実性、安定性を重視しており、今回リリースされたWagmi v2にもその思想がバッチリ反映されています。
大きな変更点
TanStack Queryのフルサポート
今までもwagmiの内部ではTanStack Queryが使用されていましたが、ユーザから細かいオプションの設定はできませんでした。
しかし、v2では以下のようにキャッシュ設定が可能になっており、パフォーマンスの向上に役立てられます。
TanStack QueryのdevToolを使ってキャッシュの状態をチェックすることもできます。
const result = useReadContract({
abi,
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
functionName: 'totalSupply',
query: { // TanStack Queryのオプション
gcTime: 1000 * 60 * 60
staleTime: 1000 * 5,
...
}
})
また、hooksの戻り値としてqueryKey
が取得できるようになっています。このqueryKeyを利用してTanStack Query同様にinvalidateも可能です。
以下はユーザがボタンを押すとinvalidateする実装例です。
import { useBalance } from 'wagmi'
function App() {
// 1. Extract `queryKey` from the useBalance Hook.
const { queryKey } = useBalance()
return (
<button
onClick={async () => {
// 2. Invalidate the query when the user clicks "Invalidate".
await queryClient.invalidateQueries({ queryKey })
}}
>
Invalidate
</button>
)
}
function Example() {
// 3. Other `useBalance` Hooks in your rendered React tree will be refetched!
const { data: balance } = useBalance()
return <div>{balance}</div>
}
さらに、以下ドキュメントに従って設定を行うと、localStorage
にデータを保存することもできます。
他にもTanStack Queryの便利な機能が使えるようになっているため、気になる方はドキュメントを見てみてください。
mutation関数の形が変わった
TanStack Queryに倣い、mutation関数の引数はhooksではなく関数側に設定するよう変更が入っています。
import { useSignMessage } from 'wagmi'
- const { signMessage } = useSignMessage({ message: 'foo bar baz' })
+ const { signMessage } = useSignMessage()
<button
- onClick={() => signMessage()}
+ onClick={() => signMessage({ message: 'foo bar baz' })}
>
Sign message
</button>
上記のuseSignMessage
だけでなく、よく使われるであろうuseWriteContract
にも変更が入っているため、そこそこ影響範囲は広いと思います。
watchプロパティ削除
blockごとに値を再取得してくれるwatch
というプロパティが削除されました。
これは上記のTanStack Queryサポートに伴い、以下のようにユーザ側でハンドリングできるようになったことが要因かと思われます。
+ import { useQueryClient } from '@tanstack/react-query'
+ import { useEffect } from 'react'
+ import { useBlockNumber, useBalance } from 'wagmi'
+ const { data: blockNumber } = useBlockNumber({ watch: true })
+ const { data: balance, queryKey } = useBalance({
+ address: '0x4557B18E779944BFE9d78A672452331C186a9f48',
- watch: true,
+ })
+ useEffect(() => {
+ queryClient.invalidateQueries({ queryKey })
+ }, [blockNumber])
今まではwatch: true
のようなコードを書けば実現できていましたが、少しコード量が増えてしまいます。
ですが、ここには 「多少コードが増えたとしても、内部コードが減ることとユーザにコントロールを与えるほうが良い」 というwagmiの思想が出ているようです。
例えば、上記のコードはuseEffect内に処理を追加することで、5blockごとに再取得する、といった処理にユーザ側で簡単に変更が可能です。
suspenseプロパティ削除
個人的には少し残念なのですが、suspense
プロパティが削除になっています。
一応以下のようにquery部分を取り出してTanStack QueryのuseSuspenseQuery
に突っ込むことで実現はできるようですが、冗長だなと感じます。
import { useSuspenseQuery } from '@tanstack/react-query'
import { useConfig } from 'wagmi'
import { getBalanceQueryOptions } from 'wagmi/query'
const config = useConfig()
const options = getBalanceQueryOptions(config, { address: '0x…' })
const result = useSuspenseQuery(options)
将来的にuseSuspenseReadContract
のようなhooksを作成して対応する予定はあるみたいですが、すぐではないとのことです。
usePrepareContract→useSimulateContract
同チームが開発しているviemと同名になるように変更されました。
(他にもuseContractWrite
がuseWriteContract
に変わったりと微妙に変更が入ってます)
EIP-6963対応
EIP-6963は、複数のウォレットが同時に開いていると、ユーザが本当に選びたいウォレットと接続できない問題に対応したEIPです。
例えば、MetaMaskとRabbyの拡張機能がインストールされており、MetaMask→Rabbyの順で読み込まれるとします。この場合、Rabbyが1つしかないwindow.ethereumの席を奪い取るため、ユーザはMetaMaskとは接続することができません。
EIP-6963の詳しい説明は以下が神記事なので割愛させていただきます。
SSR対応
以下の設定を行うことで、SSR時にHydrationエラーが出ることを回避できるようになりました。
import { createConfig, http } from 'wagmi'
import { mainnet, sepolia } from 'wagmi/chains'
const config = createConfig({
chains: [mainnet, sepolia],
+ ssr: true,
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
},
})
Third-party Wallet Libraryについて
Wallet Connecor API周りで変更があり、 Third-party Wallet Libraryは2024/1/8現在wagmi v2では動作しません。
ただし、以下のように各ライブラリで対応は進められているようです。
Rainbowkit
対応中Issue
Connectkit
対応中Issue
Web3Modal
対応中PR(中の人によるとあと1週間くらいでマージされるらしい?)
Dynamic
OSSではないので不明
chain関連の型安全
異常なchainIDを設定しようとした場合、それを静的解析時に検知できるようになりました。
例えば、以下のような設定で実装をしていたとします。
export const config = createConfig({
chains: [mainnet, sepolia],
transports: {
[mainnet.id]: http(), // chainID: 1
[sepolia.id]: http(), // chainID: 11155111
},
})
この時に以下のように設定にないchainIDを代入すると、エディター上で警告を出してくれます。
useBlockNumber({ chainId: 123 })
この機能を使うためには、上記のcreateConfig
を行っているのと同じファイルに以下実装が必要です。
declare module 'wagmi' {
interface Register {
config: typeof config
}
}
おまけ
色々触るのに使っていたリポジトリ
後書き
まだまだ触れておらず紹介できていない機能も多々ありますが、何かの役に立てば幸いです!
補足:v2への移行はまだいいや、という方は以下からv1のドキュメントが見られます。
ただし、v2の新機能はv1には搭載されない方針みたいです。
Discussion