React

@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

Terminal
$
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.

client.ts
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.

providers.tsx
"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 } lub null. signer jest null dla portfeli tylko do odczytu.
  • useConnect(client) / useDisconnect(client) — zwracają ActionResult, którego dispatch (oraz dispatchAsync) uruchamia akcję, a isRunning, status, data, error i reset ś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-reconnect
if (connected) {
return (
<div>
<p>{connected.account.address}</p>
<button onClick={() => disconnect.dispatch()}>Disconnect</button>
</div>
);
}
return (
<div>
{wallets.map((wallet) => (
<button
key={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: ClientProvider to jedyny dostawca, którego potrzebujesz; pobierz klienta przez useClient<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?

Spis treści

Edytuj stronę