@solana/react は1つのプロバイダーを通じてコンポーネントツリーにKitクライアントを提供し、フックはそこからRPCデータ、サブスクリプション、ウォレットの状態を読み取ります。ブラウザウォレットフックは @solana/kit-plugin-wallet/react に含まれており、同じプロバイダーを読み取ります — 別途ウォレットプロバイダーは必要ありません。
インストール
$npm install @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-wallet @solana/react
クライアントのビルド
クライアントはモジュールスコープで、Reactツリーの外側で一度だけビルドします。ブラウザでは、walletSigner が接続されたウォレットを手数料支払者かつアイデンティティとして設定します。
import { createClient } from "@solana/kit";import { solanaRpc } from "@solana/kit-plugin-rpc";import { walletSigner } from "@solana/kit-plugin-wallet";export const client = createClient().use(walletSigner({ chain: "solana:devnet" })).use(solanaRpc({ rpcUrl: "https://api.devnet.solana.com" }));export type AppClient = Awaited<typeof client>;
walletSigner は client.wallet(Wallet Standard の検出と接続)を追加し、solanaRpc は client.rpc と client.sendTransaction ヘルパーを追加します。後から非同期で解決するプラグインを追加した場合でも型が正しく保たれるよう、クライアント型を Awaited<> でラップしてエクスポートし、その AppClient をすべての useClient 呼び出しに渡してください。
ツリーを一度ラップする
ClientProvider がクライアントを提供します。データフック(useRequest、useSubscription、useTrackedData)は useClient を介してクライアントを読み取ります。以下のウォレットフックには、最初の引数として同じクライアントを明示的に渡す必要があります。
"use client";import { ClientProvider } from "@solana/react";import { client } from "./client";export function Providers({ children }: { children: React.ReactNode }) {return <ClientProvider client={client}>{children}</ClientProvider>;}
ウォレットフック
ウォレットフックには、ウォレットプラグイン(例:walletSigner)がインストールされたクライアントが必要です。useClient<AppClient>() でクライアントを取得し、各フックの最初の引数として渡してください — これにより、コンテキストルックアップに依存せず、アプリ全体でエンドツーエンドの型安全性が保たれます。
useWallets(client)— クライアントのチェーンで検出された Wallet Standard ウォレット。useWalletStatus(client)—"pending" | "disconnected" | "connecting" | "connected" | "disconnecting" | "reconnecting"。useConnectedWallet(client)—{ account, signer, wallet }またはnull。 読み取り専用ウォレットの場合、signerはnullになります。useConnect(client)/useDisconnect(client)—ActionResultを返します。そのdispatch(およびdispatchAsync)がアクションを実行し、isRunning、status、data、error、resetでその結果を追跡します。
"use client";import {useConnect,useConnectedWallet,useDisconnect,useWallets,useWalletStatus} from "@solana/kit-plugin-wallet/react";import { useClient } from "@solana/react";import type { AppClient } from "./client";function WalletPanel() {const client = useClient<AppClient>();const status = useWalletStatus(client);const wallets = useWallets(client);const connected = useConnectedWallet(client);const connect = useConnect(client);const disconnect = useDisconnect(client);if (status === "pending") return null; // wait out auto-reconnectif (connected) {return (<div><p>{connected.account.address}</p><button onClick={() => disconnect.dispatch()}>Disconnect</button></div>);}return (<div>{wallets.map((wallet) => (<buttonkey={wallet.name}disabled={connect.isRunning}onClick={() => connect.dispatch(wallet)}>Connect {wallet.name}</button>))}</div>);}
トランザクションの送信
useClient は公開したクライアントをそのまま返します。生成されたプログラムクライアントで instructions を構築し、client.sendTransaction を通じて送信します。
"use client";import { address, lamports } from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";import { useClient } from "@solana/react";import { useConnectedWallet } from "@solana/kit-plugin-wallet/react";import type { AppClient } from "./client";function SendSol({ destination }: { destination: string }) {const client = useClient<AppClient>();const connected = useConnectedWallet(client);async function handleSend() {if (!connected?.signer) return;const transfer = getTransferSolInstruction({source: connected.signer,destination: address(destination),amount: lamports(10_000_000n) // 0.01 SOL});const result = await client.sendTransaction([transfer]);console.log("sent", result.context.signature);}return (<button disabled={!connected?.signer} onClick={handleSend}>Send 0.01 SOL</button>);}
useClient にエクスポートした AppClient 型を渡すことで、フックはプラグインで拡張されたフルクライアントを取得し、client.rpc と client.sendTransaction が適切に型付けされます。
データの読み取り
@solana/react にはクライアントを通じてデータを読み取るフックが含まれています:
useRequest(source)— 単発のRPC読み取り。{ data, error, status, refresh }を返します。useSubscription(source)— ライブサブスクリプション。{ data, error, reconnect, status }を返します。useTrackedData(spec)— サブスクリプションによって最新の状態に保たれる、RPCをシードとした値。
"use client";import { address } from "@solana/kit";import { useClient, useRequest } from "@solana/react";import { useMemo } from "react";import type { AppClient } from "./client";function Balance({ owner }: { owner: string }) {const client = useClient<AppClient>();const source = useMemo(() => client.rpc.getBalance(address(owner)),[client, owner]);const { data, status, refresh } = useRequest(source);if (status === "fetching") return <p>Loading…</p>;if (status === "error") return <p role="alert">RPC error</p>;return (<div><p>Lamports: {data?.value.toString()}</p><button onClick={() => refresh()}>Refresh</button></div>);}
ソースを(useMemo、または関数の場合は useCallback で)メモ化することで、フックはすべてのレンダリング時ではなく、入力が変化したときのみ再フェッチします。
キャッシュと再検証については、@solana/react/swr および @solana/react/query サブパスが、SWR および TanStack Query 向けに同じフックをラップしています。
Solana開発者向けの一般的なパターン
- プロバイダーは1つ:
ClientProviderが唯一必要なプロバイダーです。useClient<AppClient>()でクライアントを取得し、ウォレットフックに渡してください。 - サーバーコンポーネント対応: フックを呼び出すリーフコンポーネントにのみ
"use client"を付けてください。サーバーでの読み取りはウォレットなしのプレーンなKit RPCクライアントで行えます。 - テスト: モック化したクライアントを
ClientProvider経由で提供することで、ウォレットやRPCレスポンスをシミュレートできます。
2つのフックファミリー、同じ名前
useSignIn と useSignMessage は @solana/react(UiWalletAccount 引数を取る)と @solana/kit-plugin-wallet/react(代わりに client を取り、ActionResult を返す)の両方に存在します。上記のクライアントパターンでは @solana/kit-plugin-wallet/react バージョンを使用してください。古い @solana/react のウォレットフックは置き換えが進んでいます。
このガイドと Kitクライアントの概要 を併せて参照し、各フックが読み取るクライアントについて理解を深めてください。
Is this page helpful?