English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french

简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE คนไทย Français русский

回答

收藏

5.3 从合同中读取数据

开源社区 开源社区 8212 人阅读 | 0 人回复 | 2025-03-11

目前,我们已经实现了最终用户授权功能,以便与我们的合约进行交互。
现在,让我们将 DApp 与第 5 章中部署的实际合约连接起来。
您需要注意一些要求,以便在本课和下一课中正确使用我们的步骤:
  • 我们将使用 testnet。请确保已将第 4 章/第 5 课中的合约部署到 testnet。
  • 请确保在第 4 章/第 5 课中已为您的合约部署了正确的初始数据,即:
    • 计数器值
    • 最近的发件人地址
    • 所有者地址 - 这必须是您的有效 testnet 钱包地址,因为您将执行取款操作,而且您还记得,我们的合同逻辑将拒绝任何非所有者的取款尝试。
      ) P3 l. i% }2 [' F$ \
  • 确保你有 testnet 代币。您可以在这里轻松获得 (https://t.me/testgiver_ton_bot)。
    % u) D0 L4 ~. k
此时,我假设你已经将第 4 章/第 5 课中的合约部署到了 testnet,并知道了它的地址。
这是我的合约地址:
  1. EQCS7PUYXVFI-4uvP1_vZsMVqLDmzwuimhEPtsyQKIcdeNPu
    / ^2 s$ h1 M# T* M, X/ H
复制代码
大家还记得,我们在编写测试时已经与我们的合约进行了一些交互。我们必须创建一个包装文件,它可以帮助我们向合约发送内部信息,还可以运行 getter 方法。令人惊喜的是,我们可以使用同一个包装文件:)
我们 DApp 的合约包装文件现在位于 src/contracts/MainContract.ts.
现在我们有了一个合适的合约包装,但如何才能真正从浏览器与链上合约建立连接呢?在第 3 章中,我们检测了合约是否已部署,并使用了 TON 库中的 TonClient 实例。它使用 TON access RPC 提供者从链上获取信息,并向我们的合约发送请求。我们将在本课中使用相同的逻辑。
在开始之前,让我们做一件 "非常 React "的事情,我们将实现一个通用的 React 钩子,它将帮助我们初始化异步对象。我们将用它来连接 TonClient。
创建包含以下内容的文件 src/hooks/useAsyncInitialize.ts:
  1. import { useEffect, useState } from "react";7 H. |, E3 [: T& u7 Y
  2. 3 o0 M$ T- `, A3 T5 o
  3. export function useAsyncInitialize<T>(+ D, }1 M4 @  {2 _$ r! f8 p$ G
  4.   func: () => Promise<T>,
    ! Z' }6 D" z9 N& U  P' Y0 o/ G" |" P* i
  5.   deps: any[] = []) P: w) B" ?- Y4 c) c- q
  6. ) {& w$ t# f% H; e1 K
  7.   const [state, setState] = useState<T | undefined>();8 x8 \3 a. @7 G# b
  8.   useEffect(() => {" T; r+ s8 m5 P" U  ]/ H
  9.     (async () => {
    ' p2 |( G5 o  K: F$ b
  10.       setState(await func());3 s+ a9 c( g! d8 ?! p3 p2 y0 c
  11.     })();
    8 B1 g: t8 v; o" C) K/ U
  12.   }, deps);' z8 M6 A0 m" `$ D

  13. 6 X0 k1 _4 H  s; C" x& N& a
  14.   return state;% G4 A1 _: g; h1 d# M, k5 }5 I  R
  15. }
复制代码
接下来,我们将创建另一个依赖于 useAsyncInitialize 的 React 钩子,并在应用程序中初始化 RPC 客户端。如上所述,我们将使用 TON Access,它将免费为我们提供无节流的 API 访问。它也是去中心化的,是访问网络的首选方式。
创建包含以下内容的文件 src/hooks/useTonClient.ts:
  1. import { getHttpEndpoint } from '@orbs-network/ton-access';( U6 ]3 g& R, ~0 b3 F+ m+ Z* @
  2. import { TonClient } from 'ton';
    4 w! C" P( C. `
  3. import { useAsyncInitialize } from './useAsyncInitialize';# c& K2 x  y# O# ^& u! Y. H

  4. 7 U- y8 y% n6 ?% A
  5. export function useTonClient() {
    ) U" `5 t- J0 ~
  6.   return useAsyncInitialize(
    + h, `5 x0 V3 J" x
  7.     async () =>* `* d9 r! w$ @
  8.       new TonClient({$ Z9 w% X# X2 T+ i. o3 r3 s6 q
  9.         endpoint: await getHttpEndpoint({ network: 'testnet' }),9 j' s- }$ P; G) u9 v" ^
  10.       })
    # |1 c) T7 ^. u/ A8 T
  11.   );
    - d; r7 m2 u' C, `
  12. }
复制代码
让我们再创建一个名为 useMainContract() 的钩子,它将接受已部署合约的链上地址,并运行我们合约的getter方法(借助包装器的 .getData() 方法)。
该钩子的代码将如下所示:
请务必将合约地址替换为已部署合约的地址
  1. import { useEffect, useState } from "react";  U- s5 m6 W  t! ?9 g
  2. import { MainContract } from "../contracts/MainContract";
    $ W; p5 m- e  E7 ~. {2 N, t. \; ?
  3. import { useTonClient } from "./useTonClient";
    * A; ~9 j8 g0 P
  4. import { useAsyncInitialize } from "./useAsyncInitialize";
    , i) J8 _. q; l+ Z: h( g% H! Q
  5. import { Address, OpenedContract } from "ton-core";
    8 p/ L  B  Z# v) v% k4 X" t

  6. $ W* W, F( V0 b+ @3 @( S$ }! j
  7. export function useMainContract() {: F; H( ^9 w- d4 s6 O
  8.   const client = useTonClient();. S3 S) D7 f8 M5 K
  9.   const [contractData, setContractData] = useState<null | {
    % }& \- u4 p  b) r- O# I8 _. H
  10.     counter_value: number;
    3 H; z+ Y$ j! ?5 R: ~
  11.     recent_sender: Address;
      m7 ?1 j7 {0 J. l+ G+ S; Y
  12.     owner_address: Address;9 y1 y# _5 S7 ]
  13.   }>();
    ) Q( Q5 H) J: I9 H* Y0 C
  14. 1 m$ S3 L- A$ f! n) [# ?% H- P, O
  15.   const mainContract = useAsyncInitialize(async () => {
    - W1 ~+ K/ J( L- o
  16.     if (!client) return;% |* i; o1 [, t! T6 u
  17.     const contract = new MainContract(
    ! q- p2 A. |7 f  z) N3 n6 W
  18.       Address.parse("EQCS7PUYXVFI-4uvP1_vZsMVqLDmzwuimhEPtsyQKIcdeNPu") // replace with your address from tutorial 2 step 8) P1 x2 {8 X* H  x& ~2 B3 E3 Y' W
  19.     );1 V( }* L3 [6 z4 p2 [- O, v" p' R
  20.     return client.open(contract) as OpenedContract<MainContract>;( a9 O+ @( e) A0 N6 Q0 S
  21.   }, [client]);
      ]! t" ?5 L1 t/ N2 V# m4 e
  22. 4 I+ V/ }" r' E& E9 C" w( j
  23.   useEffect(() => {& K3 k6 Q. Q3 Q- N$ _& Z+ _
  24.     async function getValue() {
    6 D/ z/ }  n3 P& K: ]* }7 f
  25.       if (!mainContract) return;9 [  C. [2 h' a
  26.       setContractData(null);
    2 c4 [5 N. V' C9 P
  27.       const val = await mainContract.getData();* p) u" e9 `6 J! Q/ v' |, ?/ l" S# F
  28.       setContractData({9 E/ f. l9 E9 V: U0 m1 Z
  29.         counter_value: val.number,
    ; g# h6 e- X0 H- I! V* t8 D
  30.         recent_sender: val.recent_sender,0 }" [9 Z, Q, a. Z; @2 o: A6 n
  31.         owner_address: val.owner_address,
    " T8 w' M, ^& r, O* i
  32.       });
    ( @+ _. I2 P2 i% h: y' h+ H( o
  33.     }9 R0 B. x1 f, W3 \. f/ n
  34.     getValue();  o# ]8 L5 p/ g- C4 ^9 u
  35.   }, [mainContract]);# K) K7 S; y( j* D2 C
  36. 0 y0 q' N( w  n7 a- m/ i
  37.   return {
    / Q  M5 U% z1 W/ I
  38.     contract_address: mainContract?.address.toString(),  P' i! G4 q- n
  39.     ...contractData,
    ( n8 X8 H8 I: \3 C  m& k% B
  40.   };
    7 _0 e# P1 M/ y
  41. }
复制代码
至此,我们已准备好将从链中读取的数据呈现在我们的界面上。我们用以下代码更新 src/App.tsx
  1. import "./App.css";
    ' g& D& o1 S+ A- d
  2. import { TonConnectButton } from "@tonconnect/ui-react";7 h( `) ^: @: h( n+ y. K
  3. import { useMainContract } from "./hooks/useMainContract";* T7 E% @# b  u2 w
  4. $ e) G7 g! ~6 g
  5. function App() {9 j( r: [+ q' H9 p
  6.   const {* R4 X+ ~3 Z6 k+ _3 x
  7.     contract_address,% G& V0 r& F/ {9 d* p" n1 Z* F
  8.     counter_value,
    $ v+ a3 o" k% M! Y$ ^
  9.     recent_sender,
    # g- x9 t2 d' I& f% s
  10.     owner_address,
    0 w& I, W* C2 h
  11.     contract_balance,
    : M+ D% y$ B1 `# ~$ b
  12.   } = useMainContract();$ a* D' ^4 \9 b  m
  13.   return (% E4 S5 l9 U5 }7 e+ @
  14.     <div>
    9 u! A4 n0 x& k5 G
  15.       <div>
    4 i: {! r% E# U& A+ W; q/ p: F5 p
  16.         <TonConnectButton />- {7 b9 \& F5 Y9 f; j, a
  17.       </div>) q( i) w, K! F; B2 R$ ~
  18.       <div>
    2 L8 I. f9 C; [; e; E. N
  19.         <div className='Card'>( Z- I" K1 G( v! |% G; ]
  20.           <b>Our contract Address</b>: W, h3 F" p' e/ e" {
  21.           <div className='Hint'>{contract_address?.slice(0, 30) + "..."}</div>5 W7 {$ l( ~; D0 E/ s  n2 n4 y
  22.           <b>Our contract Balance</b>
    ' t4 y3 n* Z0 R5 b& f
  23.           <div className='Hint'>{contract_balance}</div>& l2 G5 v' o3 V) }$ p! [# ]; e( H
  24.         </div>
    - G% x0 @6 s2 Q/ _3 F3 n/ F
  25. 2 L& x& \& O  \, y# `* t
  26.         <div className='Card'>
      C" x* u! s0 s) K3 p, ~6 _1 c. E
  27.           <b>Counter Value</b>
    ! z6 ?$ k' ^9 [! W) H; k9 e( C
  28.           <div>{counter_value ?? "Loading..."}</div>$ K! p3 X  o: R% P8 H& H! P
  29.         </div>
    5 N8 `( R  F# ~: U, D
  30.       </div>
    5 q! m* v8 G2 w
  31.     </div>$ u( x+ w" n# p! y- ]! b
  32.   );8 p+ [  a5 A( A" G
  33. }, p- U7 S) [/ D7 M3 K; v1 Q

  34. : R% {7 E- ]1 \6 K
  35. export default App;
复制代码
很好,至此我们已经准备就绪,可以轻松从链中读取合约数据了。请注意,即使我们没有通过 TON Connect 授权,也可以读取数据,因为这是只读数据,只有当我们要执行 "写 "操作时才需要授权。
在下一课中,我们将执行这些交互式操作,发送增量、存款和取款交易。

: u$ H) h( b& u, N3 A/ V
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则