@solana/react publikuje klienta Kit w drzewie komponentów przez jednego
dostawcę, a hooki odczytują z niego dane RPC, subskrypcje i stan portfela. Hooki
portfela dla przeglądarki znajdują się w @solana/kit-plugin-wallet/react i
korzystają z tego samego dostawcy — nie ma osobnego dostawcy portfela.
Instalacja
$npm install @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-wallet @solana/react
Budowanie klienta
Zbuduj klienta raz, w zakresie modułu, poza drzewem React. W przeglądarce
walletSigner sprawia, że podłączony portfel pełni rolę zarówno płatnika opłat,
jak i tożsamości.
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 dodaje client.wallet (wykrywanie i łączenie zgodne z Wallet
Standard), a solanaRpc dodaje client.rpc oraz pomocnika
client.sendTransaction. Wyeksportuj typ klienta opakowany w Awaited<>, aby
pozostał poprawny w przypadku późniejszego dodania wtyczki rozwiązującej się
asynchronicznie, i przekaż ten AppClient do każdego wywołania useClient.
Opakuj drzewo raz
ClientProvider publikuje klienta. Hooki danych (useRequest,
useSubscription, useTrackedData) odczytują go przez useClient. Hooki
portfela poniżej wymagają przekazania tego samego klienta explicite jako
pierwszego argumentu.
"use client";import { ClientProvider } from "@solana/react";import { client } from "./client";export function Providers({ children }: { children: React.ReactNode }) {return <ClientProvider client={client}>{children}</ClientProvider>;}
Hooki portfela
Hooki portfela wymagają klienta z zainstalowaną wtyczką portfela (np.
walletSigner). Pobierz go przez useClient<AppClient>() i przekaż jako
pierwszy argument każdego hooka — dzięki temu aplikacja zachowuje pełne
typowanie end-to-end zamiast polegać na wyszukiwaniu w kontekście.
useWallets(client)— portfele Wallet Standard wykryte dla łańcucha klienta.useWalletStatus(client)—"pending" | "disconnected" | "connecting" | "connected" | "disconnecting" | "reconnecting".useConnectedWallet(client)—{ account, signer, wallet }lubnull.signerjestnulldla portfeli tylko do odczytu.useConnect(client)/useDisconnect(client)— zwracająActionResult, któregodispatch(orazdispatchAsync) uruchamia akcję, aisRunning,status,data,erroriresetśledzą jej wynik.
"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>);}
Wysyłanie transakcji
useClient zwraca tego samego klienta, którego opublikowałeś. Zbuduj instrukcje
za pomocą wygenerowanego klienta programu i wyślij je przez
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>);}
Przekazanie wyeksportowanego typu AppClient do useClient daje hookowi pełny
klient rozszerzony o wtyczki, dzięki czemu client.rpc i
client.sendTransaction są typowane.
Odczyt danych
@solana/react dostarcza hooki odczytujące dane przez klienta:
useRequest(source)— jednorazowy odczyt RPC; zwraca{ data, error, status, refresh }.useSubscription(source)— aktywna subskrypcja; zwraca{ data, error, reconnect, status }.useTrackedData(spec)— wartość zasiana przez RPC, aktualizowana na bieżąco przez subskrypcję.
"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>);}
Zapamiętaj źródło (za pomocą useMemo lub useCallback dla funkcji), aby hook
ponownie pobierał dane tylko przy zmianie wejść, a nie przy każdym renderowaniu.
Do cachowania i rewalidacji ścieżki podrzędne @solana/react/swr i
@solana/react/query opakowują te same hooki dla SWR i
TanStack Query.
Typowe wzorce dla deweloperów Solana
- Jeden dostawca:
ClientProviderto jedyny dostawca, którego potrzebujesz; pobierz klienta przezuseClient<AppClient>()i przekaż go do hooków portfela. - Świadomość komponentów serwerowych: Oznacz
"use client"tylko liściowe komponenty wywołujące hooki; odczyty po stronie serwera mogą korzystać ze zwykłego klienta RPC Kit bez portfela. - Testowanie: Opublikuj mockowanego klienta przez
ClientProvider, aby symulować portfele i odpowiedzi RPC.
Dwie rodziny hooków, te same nazwy
useSignIn i useSignMessage istnieją zarówno w @solana/react (przyjmują
argument UiWalletAccount), jak i w @solana/kit-plugin-wallet/react
(przyjmują client, zwracają ActionResult). Używaj wersji z
@solana/kit-plugin-wallet/react wraz z powyższym wzorcem klienta; starsze
hooki portfela @solana/react są zastępowane.
Połącz ten przewodnik z przeglądem klienta Kit, aby zrozumieć klienta, z którego korzysta każdy hook.
Is this page helpful?