@solana/react-hooks 0.5.0 → 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,15 +13,18 @@ pnpm add @solana/react-hooks
13
13
 
14
14
  ## Minimal example
15
15
 
16
- Mount the provider once and call hooks anywhere in the subtree.
16
+ Build connectors first, create a client, and hand it to the combined provider.
17
17
 
18
18
  ```tsx
19
- import {
20
- SolanaClientProvider,
21
- useBalance,
22
- useConnectWallet,
23
- useWallet,
24
- } from '@solana/react-hooks';
19
+ import { autoDiscover, backpack, createClient, phantom, solflare } from '@solana/client';
20
+ import { SolanaProvider, useBalance, useConnectWallet, useWallet } from '@solana/react-hooks';
21
+
22
+ const walletConnectors = [...phantom(), ...solflare(), ...backpack(), ...autoDiscover()];
23
+ const client = createClient({
24
+ endpoint: 'https://api.devnet.solana.com',
25
+ websocketEndpoint: 'wss://api.devnet.solana.com',
26
+ walletConnectors,
27
+ });
25
28
 
26
29
  function WalletButton() {
27
30
  const connectWallet = useConnectWallet();
@@ -40,19 +43,23 @@ function WalletBalance() {
40
43
 
41
44
  export function App() {
42
45
  return (
43
- <SolanaClientProvider
44
- config={{
45
- endpoint: 'https://api.devnet.solana.com',
46
- websocketEndpoint: 'wss://api.devnet.solana.com',
47
- }}
48
- >
46
+ <SolanaProvider client={client} query={{ suspense: true }}>
49
47
  <WalletButton />
50
48
  <WalletBalance />
51
- </SolanaClientProvider>
49
+ </SolanaProvider>
52
50
  );
53
51
  }
54
52
  ```
55
53
 
54
+ `SolanaProvider` composes `SolanaClientProvider` and `SolanaQueryProvider` with SWR v2-aligned defaults
55
+ (`revalidateOnFocus`/`revalidateOnReconnect`/`revalidateIfStale` are `true`, `dedupingInterval` is `2000`,
56
+ `focusThrottleInterval` is `5000`). Override them via the `query.config` prop or per-hook `swr` options.
57
+ Prefer passing a `client`; `config`-based setup on `SolanaClientProvider` is still available for bespoke
58
+ composition.
59
+
60
+ Every hook exposes `UseHookNameParameters` / `UseHookNameReturnType` aliases so wrapper components stay in
61
+ sync with the public API.
62
+
56
63
  ## Hooks at a glance
57
64
 
58
65
  - `useWallet`, `useConnectWallet`, `useDisconnectWallet` – read or update the current wallet session.
@@ -318,7 +325,7 @@ Poll or refetch the cluster's latest blockhash.
318
325
  import { SolanaQueryProvider, useLatestBlockhash } from '@solana/react-hooks';
319
326
 
320
327
  function BlockhashTicker() {
321
- const latest = useLatestBlockhash({ refreshInterval: 20_000 });
328
+ const latest = useLatestBlockhash({ swr: { refreshInterval: 20_000 } });
322
329
  if (latest.status === 'loading') return <p>Fetching blockhash…</p>;
323
330
  if (latest.status === 'error') return <p role="alert">Failed to fetch blockhash.</p>;
324
331
 
@@ -343,7 +350,15 @@ export function BlockhashCard() {
343
350
  ### Program accounts
344
351
 
345
352
  ```tsx
346
- import { SolanaClientProvider, SolanaQueryProvider, useProgramAccounts } from '@solana/react-hooks';
353
+ import { autoDiscover, backpack, createClient, phantom, solflare } from '@solana/client';
354
+ import { SolanaProvider, SolanaQueryProvider, useProgramAccounts } from '@solana/react-hooks';
355
+
356
+ const walletConnectors = [...phantom(), ...solflare(), ...backpack(), ...autoDiscover()];
357
+ const client = createClient({
358
+ endpoint: 'https://api.devnet.solana.com',
359
+ websocketEndpoint: 'wss://api.devnet.solana.com',
360
+ walletConnectors,
361
+ });
347
362
 
348
363
  function ProgramAccountsList({ programAddress }) {
349
364
  const query = useProgramAccounts(programAddress);
@@ -365,11 +380,11 @@ function ProgramAccountsList({ programAddress }) {
365
380
 
366
381
  export function QueryDemo({ programAddress }) {
367
382
  return (
368
- <SolanaClientProvider config={{ endpoint: 'https://api.devnet.solana.com' }}>
383
+ <SolanaProvider client={client}>
369
384
  <SolanaQueryProvider>
370
385
  <ProgramAccountsList programAddress={programAddress} />
371
386
  </SolanaQueryProvider>
372
- </SolanaClientProvider>
387
+ </SolanaProvider>
373
388
  );
374
389
  }
375
390
  ```
@@ -407,7 +422,7 @@ function SimulationLogs({ transaction }) {
407
422
  `useProgramAccounts(address, { swr: { revalidateOnFocus: false } })`) and expose typed parameter
408
423
  and return aliases across all hooks.
409
424
  - Type helpers: use `UseHookNameParameters` / `UseHookNameReturnType` for public hooks.
410
- - Looking for examples? See `examples/react-hooks` for a ready-to-run, tabbed playground that wires
425
+ - Looking for examples? See `examples/vite-react` for a ready-to-run, tabbed playground that wires
411
426
  the provider, hooks, and mock UIs together across wallet/state, transaction, and query demos.
412
427
 
413
428
  ## Scripts
@@ -14,16 +14,18 @@ var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
14
14
  var __defProp = Object.defineProperty;
15
15
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
16
16
  var SolanaClientContext = react.createContext(null);
17
+ function normalizeConfig(config) {
18
+ return client.resolveClientConfig(config ?? {});
19
+ }
20
+ __name(normalizeConfig, "normalizeConfig");
17
21
  function SolanaClientProvider({ children, client: providedClient, config }) {
22
+ const normalizedConfig = react.useMemo(() => normalizeConfig(config), [config]);
18
23
  const client$1 = react.useMemo(() => {
19
24
  if (providedClient) {
20
25
  return providedClient;
21
26
  }
22
- if (!config) {
23
- throw new Error("SolanaClientProvider requires either a `client` or `config` prop.");
24
- }
25
- return client.createClient(config);
26
- }, [config, providedClient]);
27
+ return client.createClient(normalizedConfig);
28
+ }, [normalizedConfig, providedClient]);
27
29
  react.useEffect(() => {
28
30
  if (providedClient) {
29
31
  return;
@@ -601,7 +603,9 @@ function useTransactionPool(config = {}) {
601
603
  );
602
604
  const client$1 = useSolanaClient();
603
605
  const helper = client$1.helpers.transaction;
604
- const blockhashMaxAgeMs = config.latestBlockhash?.refreshInterval ?? 3e4;
606
+ const swrRefreshInterval = config.latestBlockhash?.swr?.refreshInterval;
607
+ const blockhashRefreshInterval = config.latestBlockhash?.refreshInterval ?? (typeof swrRefreshInterval === "number" ? swrRefreshInterval : void 0);
608
+ const blockhashMaxAgeMs = blockhashRefreshInterval ?? 3e4;
605
609
  const controller = react.useMemo(
606
610
  () => client.createTransactionPoolController({
607
611
  blockhashMaxAgeMs,
@@ -883,14 +887,15 @@ function SolanaQueryProvider({
883
887
  return /* @__PURE__ */ jsxRuntime.jsx(QuerySuspenseContext.Provider, { value: suspense, children: /* @__PURE__ */ jsxRuntime.jsx(useSWR.SWRConfig, { value, children }) });
884
888
  }
885
889
  __name(SolanaQueryProvider, "SolanaQueryProvider");
886
- function SolanaProvider({ children, client, config, query, walletPersistence }) {
890
+ function SolanaProvider({ children, client: client$1, config, query, walletPersistence }) {
887
891
  const shouldIncludeQueryLayer = query !== false && query?.disabled !== true;
888
892
  const queryProps = shouldIncludeQueryLayer && query ? query : {};
889
893
  const persistenceConfig = walletPersistence === false ? void 0 : walletPersistence ?? {};
890
894
  const storage = persistenceConfig ? persistenceConfig.storage ?? getDefaultStorage() : null;
891
895
  const storageKey = persistenceConfig?.storageKey ?? DEFAULT_STORAGE_KEY;
892
896
  const persistedState = persistenceConfig ? readPersistedState(storage, storageKey) : { legacyConnectorId: null, state: null };
893
- const clientConfig = config && persistenceConfig ? { ...config, initialState: config.initialState ?? persistedState.state ?? void 0 } : config;
897
+ const normalizedConfig = config ? client.resolveClientConfig(config) : client.resolveClientConfig();
898
+ const clientConfig = persistenceConfig ? { ...normalizedConfig, initialState: normalizedConfig.initialState ?? persistedState.state ?? void 0 } : normalizedConfig;
894
899
  const content = shouldIncludeQueryLayer ? /* @__PURE__ */ jsxRuntime.jsx(
895
900
  SolanaQueryProvider,
896
901
  {
@@ -900,7 +905,7 @@ function SolanaProvider({ children, client, config, query, walletPersistence })
900
905
  children
901
906
  }
902
907
  ) : children;
903
- return /* @__PURE__ */ jsxRuntime.jsxs(SolanaClientProvider, { client, config: clientConfig, children: [
908
+ return /* @__PURE__ */ jsxRuntime.jsxs(SolanaClientProvider, { client: client$1, config: clientConfig, children: [
904
909
  persistenceConfig ? /* @__PURE__ */ jsxRuntime.jsx(
905
910
  WalletPersistence,
906
911
  {