@solana/react публикует 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 возвращает тот же клиент, который вы опубликовали. Создайте инструкции с помощью сгенерированного клиента программы и отправьте их через 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>);}
Передача экспортированного типа AppClient в useClient даёт хуку полный клиент с расширениями плагинов, благодаря чему 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
- Один провайдер:
ClientProvider— единственный провайдер, который вам нужен; получайте клиент черезuseClient<AppClient>()и передавайте его в хуки кошелька. - Поддержка серверных компонентов: помечайте
"use client"только конечные компоненты, вызывающие хуки; серверные чтения могут использовать обычный Kit RPC-клиент без кошелька. - Тестирование: публикуйте замоканный клиент через
ClientProviderдля имитации кошельков и ответов RPC.
Два семейства хуков с одинаковыми именами
useSignIn и useSignMessage существуют как в @solana/react (принимают аргумент UiWalletAccount), так и в @solana/kit-plugin-wallet/react (принимают client, возвращают ActionResult). Используйте версии из @solana/kit-plugin-wallet/react с паттерном клиента выше; устаревшие хуки кошелька из @solana/react постепенно заменяются.
Дополните это руководство обзором Kit-клиента, чтобы понять, какой клиент использует каждый хук.
Is this page helpful?