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

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

回答

收藏

如何为 TON 测试网红包智能合约开发前端(第三部分)

开源社区 开源社区 5433 人阅读 | 0 人回复 | 2025-03-20

本帖最后由 riyad 于 2025-3-20 21:47 编辑
" ], p* }+ b4 l9 ]. f7 Y3 `( V1 }9 T# J9 D3 z# Q, ~! \
在前两篇教程中,我已经完成了红包智能合约的编写、编译和部署到 TON 测试网。今天,我们进入第三部分:开发一个前端界面,让用户可以直观地与红包合约交互。我使用 Vite + React + TypeScript 搭建了前端项目,并集成了 TON 钱包连接功能。以下是我的开发过程和完整代码,欢迎大家参考!) X5 w+ `. a& b6 ^

4 h7 K" T) Z* G  _  B1 c前提条件1 k$ }& M  p; m0 o1 L) l9 O3 @
在开始之前,确保你已完成以下步骤:: [3 K5 V* C% s: ^

1 y# F+ a2 v! c/ i/ i
  • 完成前两部分:你已经编写、编译并部署了红包智能合约到 TON 测试网。
  • 测试网钱包:用户需要一个支持测试网的 TON 钱包(如 TON Wallet),并通过 @testgiver_ton_bot 获取测试币。
  • Node.js 环境:确保已安装 Node.js(建议使用最新 LTS 版本)。
    & @' [: u6 N: e1 Y3 m+ Y# ]9 ?& B
. z& x* J7 p" R* c! s
项目文件夹结构
" K  @. N# j. G# u我使用 Vite 创建了一个 React + TypeScript 项目,项目名为 TON-RED-PACKET。以下是项目目录结构
/ y& e" l" Y7 ?/ y: d
0 Q6 C& j, Q- T% @0 M" O, `. r: W  N' ]" J" @

' S7 k3 r1 [, e8 Z7 ]目录说明:  {) a9 m  p3 J1 i, w9 h& x" i
components/:存放可复用的组件。
+ R2 |: V6 \8 Y* D
  • WalletConnect.tsx:钱包连接组件。
  • RedPacketContext.tsx:红包上下文,用于管理全局状态。1 G+ r  O7 s! _; z5 Z7 a" Y# N
pages/:存放页面组件。3 P! L, O7 @: w& c2 i! b
  • ClaimPacketPage.tsx:领取红包页面。
  • CreatePacketPage.tsx:创建红包页面。
  • HomePage.tsx:首页。
  • LoginPage.tsx:登录页面。
    * k1 }4 `7 \4 N8 ?; _
App.tsx 和 App.css:主应用组件和样式。
$ T6 m0 Q- t* Bindex.css 和 main.tsx:全局样式和入口文件。
* g  B% W+ {! Vvite-env.d.ts:Vite 环境声明文件。* P% P9 \3 l7 G% o7 [: G' h9 u1 c
其他配置文件:如 package.json、tsconfig.json 等。
1 u( _1 m; J. n; w0 I# |/ U5 z步骤 1:创建前端项目4 m1 z2 ~6 J% v# Z3 r" P8 ^
我使用 Vite 快速搭建了一个 React + TypeScript 项目。以下是创建步骤:$ R, N( w: c: K2 v: H3 h/ |
+ e5 T* t7 x" n& `6 ]
初始化项目: 在终端运行:# S/ M$ t/ b2 q4 O
  1. npm create vite@latest TON-RED-PACKET -- --template react-ts
复制代码
选择 react-ts 模板,项目会自动生成基础结构。
8 a! `6 {' `$ q* v4 F1 o1 F2 d( B6 h; M2 J
3 F0 N& p0 M( a. M- s# H进入项目目录并安装依赖:
8 n% I9 g* U6 g
  1. cd TON-RED-PACKET
    7 c/ Z3 P4 L7 B2 J4 w
  2. npm install
复制代码
安装额外的依赖: 为了实现钱包连接和页面交互,我安装了以下依赖:
  Y* D; ~% Q9 b+ Z3 Y, H
/ F5 r3 v; i: O  k! A
  1. npm install @ton/ton @tonconnect/ui-react antd-mobile react-router-dom
复制代码
打开浏览器,访问 http://localhost:5173,你会看到 Vite 的默认页面。
' x* |" b# A% Y; g
$ x) c/ Y: x6 s' a& }
' T" p/ o/ ~$ X0 {$ r+ g0 Y# W, d* I- Q  |
步骤 2:设置入口文件和全局样式# B- C1 B3 f$ U% Y7 v6 X: h
我修改了 main.tsx 和 index.css,设置了应用的入口和全局样式。
$ R1 p9 ]. d8 l7 J1 t  L4 X6 y) I8 ?* p
2.1 main.tsx
2 k8 l3 v8 G3 I2 ^main.tsx 是应用的入口文件,我在这里设置了 React Router 和全局上下文:" @. H  i; Q& t) N% a( s3 W
  1. import { StrictMode } from 'react'
    5 _0 [0 n; |" G
  2. import { createRoot } from 'react-dom/client'$ w5 s% a1 K% J5 K
  3. import { BrowserRouter } from 'react-router-dom';; x4 c; H/ f' u
  4. import { RedPacketProvider } from './context/RedPacketContext';  o; Y6 J) h2 o
  5. import './index.css'
    & z2 F$ Y5 V! P: k; j2 c& s. e, z
  6. import App from './App.tsx'
    : \1 F1 w& z- Z8 @) L$ L1 T

  7. ) R! i# R( T" T5 M$ J% \5 R% p6 J
  8. createRoot(document.getElementById('root')!).render(  }) G1 |$ u9 {. S
  9.   <StrictMode>/ o) w4 S0 H; e" _
  10.     <RedPacketProvider>
    ( v6 P& e+ A2 ]! }4 p+ _  T/ @
  11.       <BrowserRouter>0 e5 `5 K8 X8 V$ p1 `+ x: J
  12.           <App />
    - y7 h% L/ h; R$ u
  13.       </BrowserRouter>5 y! W: x3 d: a
  14.     </RedPacketProvider>
    $ o) l6 @' J, c' k# P
  15.   </StrictMode>,
    5 A: H6 u, H5 b  t5 @( V
  16. )
复制代码
  1. :root {
    9 T) }6 v1 ~8 O. K6 p5 K
  2.   font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
    5 L0 w8 q( A1 O$ @3 Y6 o5 ^
  3.   line-height: 1.5;6 [, Q% j# E8 j% p( [( d# I2 R0 s
  4.   font-weight: 400;7 P) W  J6 j7 r% {% S
  5. ( x7 R, J, K2 y4 {0 j
  6.   color-scheme: light dark;
    $ g& ]0 q# h8 U- [. q+ n' N/ s: W
  7.   color: rgba(255, 255, 255, 0.87);
    7 \8 z% I' t& S0 ?/ r
  8.   background-color: #242424;
    ' |6 i7 x7 w, M0 ^; m

  9. % x% h% C! F! k
  10.   font-synthesis: none;
    % j) ^2 F# r+ y1 w9 v
  11.   text-rendering: optimizeLegibility;) R$ l& [6 _8 K
  12.   -webkit-font-smoothing: antialiased;
    & T$ y* W* @7 Q$ F3 R; Q) a7 D
  13.   -moz-osx-font-smoothing: grayscale;
    4 y* H. L# z. p+ J! Z$ B% L; J
  14. }
    * `; Z  h6 B% w! Q

  15. % s$ Z: P) c) A0 G* |, K
  16. a {
    - ?: \$ J* H2 Y/ K, X, J$ E/ E' U
  17.   font-weight: 500;
    ' d& f& d& @! u& f: B+ {# R5 i) w
  18.   color: #646cff;
    3 |6 B# ]/ g2 w( ^, J0 Y
  19.   text-decoration: inherit;
    6 P- Y( a% Z9 \& H
  20. }
    2 ^9 D  _4 v. N( R* P
  21. a:hover {5 m3 H+ Y- k3 g9 t0 @  j* u# w" u
  22.   color: #535bf2;" g" r4 C$ J5 a$ O* n6 u
  23. }
    ; x- d! z% `9 }( S6 s1 @5 T) {

  24. * H( a3 x/ e2 K+ l8 R/ G
  25. body {- P# q1 A. z9 X+ K4 B) X
  26.   margin: 0;
    ' `9 q9 ]8 T& [2 N
  27.   display: flex;
    1 E8 u# Q" n8 t9 B& a" G7 x. X
  28.   place-items: center;
    & o: V* ]3 y# S9 U8 ^- i
  29.   min-width: 320px;3 b: v+ K# d6 w: S! i
  30.   min-height: 100vh;
    0 j6 j9 h3 g- z, v
  31. }' _1 ^; G0 w: O9 |  d( g

  32. / a+ `6 e8 V! t
  33. h1 {  e. @5 S, [( W8 u
  34.   font-size: 3.2em;
    ' I+ e$ E6 o6 j# D( U7 K7 ?
  35.   line-height: 1.1;, u/ g/ P6 S! S. D0 L5 N
  36. }
    & ]4 x$ D0 e+ j9 j+ `6 t# c
  37. , n7 ~4 Y. e* i- Y$ q. A- L# q+ S. y
  38. button {
      [4 |6 I6 f; j. D& @
  39.   border-radius: 8px;
    6 a0 \  \+ d8 H: a+ A8 u! A' ~/ [
  40.   border: 1px solid transparent;
    0 y2 O9 g: z$ V" G6 I) x
  41.   padding: 0.6em 1.2em;
    ( v3 e2 O2 @) a+ C$ T# ^/ x" M8 E: q
  42.   font-size: 1em;  _: d' L7 j9 n1 H4 R
  43.   font-weight: 500;% h4 _8 v7 W% C* [5 |. o; R
  44.   font-family: inherit;
    & u3 ~+ g2 [  n  z. x4 W* y
  45.   background-color: #1a1a1a;
    6 ?$ q; F3 G  b. a/ v# u+ W
  46.   cursor: pointer;( p) ?+ ~  y6 e0 P& h5 \# r
  47.   transition: border-color 0.25s;
    , P/ i: \& p+ x; b
  48. }* G# x% U9 o  m  l! N2 c
  49. button:hover {0 \# F! x* H1 r, h$ I7 Q
  50.   border-color: #646cff;6 `4 Q! c- p0 V; O3 i' l
  51. }: @4 H" e" E8 b, @2 n& A
  52. button:focus,
    9 ~! }4 _  J6 q. y9 P
  53. button:focus-visible {
    / c! d; |4 H, f- n  a9 [
  54.   outline: 4px auto -webkit-focus-ring-color;* V) }% O! t" X* \6 ^# H5 K1 ?) Q5 P
  55. }
    , W9 V- v! I) D- @. A
  56. " f5 q! P) ^( S+ C
  57. @media (prefers-color-scheme: light) {* O) [# _7 c* D
  58.   :root {
    9 B0 p+ t% {# P, B# S
  59.     color: #213547;
    4 o1 s, I1 _2 Q5 y; G' o
  60.     background-color: #ffffff;3 r4 {$ M  W" I. ?4 ^8 P; ?
  61.   }
    , \$ V6 t5 q6 y; X/ m0 O
  62.   a:hover {
    1 K5 q+ P& R* t! t# m, w
  63.     color: #747bff;: O! M/ x1 C2 k+ o' O  o
  64.   }" z( w) E2 M& u+ ^$ a$ R
  65.   button {' Q' g% R9 ?( [' a0 U& W
  66.     background-color: #f9f9f9;
    & q3 i7 T+ S9 x: h
  67.   }
    3 Y9 Q6 M3 m- o
  68. }
复制代码
  1. // WalletConnect.tsx
    0 T. M) j/ q+ @/ K3 K
  2. import React, { useEffect } from 'react';
    ; e6 M7 F: m3 [) j8 Q, @$ |) ~
  3. import { Button } from 'antd-mobile';
    # Z# t# h6 F, l' ]% \
  4. import { useNavigate } from 'react-router-dom';
    5 m' i. M) o% v9 X
  5. import { useTonAddress,TonConnectButton, useTonConnectUI } from '@tonconnect/ui-react';  // Import necessary hooks
    # G2 I  a# {. D: U8 q  V- v& t
  6. 4 Z8 P* W  \0 y  Y
  7. const WalletConnect: React.FC = () => {2 C6 |. v1 |9 K( u8 e$ y
  8.   const navigate = useNavigate();
    2 i- X, U8 O' i3 d7 u. F, L
  9.   const address = useTonAddress();  // Get the connected wallet address
    " I/ S  A$ P/ o0 u6 c0 k! ?
  10.   const [tonConnectUI] = useTonConnectUI();
    * i9 i9 E5 J* T  Z" `2 D

  11. ' O& Y, c+ J' a# `8 Q
  12.   // Redirect to HomePage once connected5 n+ y6 i9 O& x! K5 f7 N
  13.   useEffect(() => {
    & K; ^- U; |1 a2 K5 _
  14.     if (!address) {
    7 z( C5 C4 q" D
  15.       navigate('/login');  // Navigate to HomePage when wallet is connected
    + T# L0 P4 I4 d' Q3 O
  16.     }6 o3 m# R& K. u$ l2 w. @7 H, x
  17.   }, [address, navigate]);
    + T1 m8 z" W: V* g. y" l! f' W
  18. ; c$ l5 `2 h- L* w: [" R1 F4 }
  19.   // Handle Disconnect Wallet* C9 I0 q6 K, t8 l4 s7 g% n
  20.   const handleDisconnect = () => {+ q3 _; M- _# [
  21.      tonConnectUI.disconnect();
    ; c+ t; H* h: b4 y, h0 x
  22.      navigate('/login');  // Redirect to login page after disconnecting
    2 f3 W% \1 N3 U( v
  23.   };
    # F. `0 A: g( h/ J; O* Z, _

  24. , T6 X0 O8 n7 w
  25.   return (
    $ g5 C# ]/ Y9 e, \6 [2 S
  26.     <div style={{ padding: '1rem', textAlign: 'center' }}>
    - A9 d0 E2 ]* q8 @
  27.       {address ? (
      Y$ I7 Q- p9 C  Q" o
  28.         <>
    + o) ~* b, z+ Q2 e3 Y
  29.           <Button onClick={handleDisconnect}>Disconnect Wallet</Button> ; D5 f* q/ o* R# U3 \- Y
  30.         </>; M& V( R% }' b8 X9 `  O
  31.       ) : (
    ! ^0 ]- c; M5 R/ G9 l3 O
  32.         <>
    5 `3 D# {+ G$ h+ p5 k. _3 q$ b. i6 n
  33.           <TonConnectButton style={{ marginBottom: '1rem' }} />
    5 Q, c' ?$ ~) ]- L
  34.         </>( i1 |0 s' B5 U1 t4 v- v
  35.       )}
    & u! R; W) _6 @# S3 L+ d" n5 x* N
  36.     </div>; U5 |* J5 {3 U) W, i$ i" B
  37.   );
    ; [9 T  c! y/ S0 f# @% x  ~
  38. };/ a. o' ?$ B- e% M

  39. / a" F  Q* Y1 v
  40. export default WalletConnect;
复制代码
  1. import React, { createContext, useContext, useState } from 'react';
    6 ?. A7 C) z8 B5 L( ?# B( s
  2. 7 _  K* J; k6 [8 Y: r9 z
  3. export type RedPacket = {
    ; Y4 l$ m. C3 L
  4.   id: string;
    ! S" p5 w( V2 W
  5.   amount: number;- C1 k2 r; L' }
  6.   quantity: number;. z+ E* o+ B% m: W2 x% E
  7.   message?: string;
    0 Z! N2 R+ `; p& r' |! R
  8. };
    / P0 N6 ^( n, o/ ^) {
  9. # g1 D3 f# i$ f  m& R6 ^" R
  10. type RedPacketContextType = {
    8 @! T# x- o$ V; k! S' Y* L
  11.   redPackets: RedPacket[];
    3 {. k' t8 e  a8 [( L8 z
  12.   addRedPacket: (packet: RedPacket) => void;
    . Y5 x% q' H+ c  `
  13. };' t- O, D) i1 a0 G

  14. 7 B) U" M6 k6 A4 H& C/ C; ]
  15. const RedPacketContext = createContext<RedPacketContextType | undefined>(undefined);
    5 ?# ^6 P+ [/ H; o

  16. + b9 z% r' M9 b9 i" o7 S4 F
  17. export const useRedPacket = () => {4 S8 x& Y! z8 j; o$ w. A  L
  18.   const context = useContext(RedPacketContext);  M7 g4 S5 E% k3 L+ z( r) U1 k1 X
  19.   if (!context) {0 h0 O+ v4 x! M$ U: g* R4 z
  20.     throw new Error('useRedPacket must be used within a RedPacketProvider');, l/ I# m& m% v' w/ w* w
  21.   }
    2 X& f" x0 x1 }- [
  22.   return context;
    % |0 C$ P8 H9 \2 u2 m! J
  23. };
    3 C& A7 [2 X0 `' A4 u

  24. ( T7 H+ y( T9 `5 Z! o4 {7 \1 p
  25. export const RedPacketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {6 Y% b6 C( k1 t/ o$ {. s; S
  26.   const [redPackets, setRedPackets] = useState<RedPacket[]>([
    ! U' A1 a! q( ]$ z$ N8 A' ?
  27.     // Initial dummy data
    ) q) h& @  h: ]$ L
  28.     // { id: '1', amount: 100, quantity: 10, message: 'Happy New Year!' },/ D; w& D+ r' u/ a) j
  29.     // { id: '2', amount: 50, quantity: 5, message: 'Best Wishes!' },
    " z' s4 l/ L# e; N
  30.   ]);
    3 f$ A9 r- e; ?8 S/ y2 D
  31. & N0 q5 T! |' \$ L- v; a5 U
  32.   const addRedPacket = (packet: RedPacket) => {
    / o( i  O5 z- Z" L6 x4 _/ H
  33.     setRedPackets(prev => [...prev, packet]);
    2 g& O0 l. ?2 P* s# t1 N) [  h
  34.   };% G3 m& O+ s2 l: V9 T, g) R% Y8 @5 K

  35. . |& [. ]; e( f1 G. x% s$ Y
  36.   return (
    8 [  v/ l7 N* Y; J  Y& r' [* H% L
  37.     <RedPacketContext.Provider value={{ redPackets, addRedPacket }}>
    , h) [7 l% ?( N1 \) e' ^
  38.       {children}$ A: `* v3 v" L/ T% I" p
  39.     </RedPacketContext.Provider>
    + l4 j* Q( g: c6 z) r6 l5 P
  40.   );
    . Y7 V; y) @# m
  41. };
复制代码
  1. import React from 'react';
    % ]' h. F8 J. Z8 @' s2 ]
  2. import { Button, List } from 'antd-mobile';' H; o; H# D) m
  3. import { useNavigate } from 'react-router-dom';
    1 g. v! b* l1 S9 a* @2 x$ q+ I
  4. import { useRedPacket } from '../context/RedPacketContext';- Z: j3 D0 Q+ v* U! e# N! J& k

  5. + ~: p  ~# \* B$ A# i; ?7 D  U
  6. const HomePage: React.FC = () => {
    9 G  m: r& q0 [6 U4 e
  7.   const navigate = useNavigate();
    9 |) c! M- G; Y4 h
  8.   const { redPackets } = useRedPacket();% U' K/ @* ^; ^$ o

  9. 5 X2 C: v+ R1 n( r/ O* m
  10.   return (
    : _# F+ S8 E$ V0 k% j/ g' E5 R
  11.     <div style={{ padding: '1rem' }}>2 r3 U( W7 ?4 l/ x
  12.       <h2>Home</h2>) u+ M, V% ?( I. J! p
  13.       <Button color="primary" onClick={() => navigate('/create')} block>/ a# [& \: b9 E2 {* j9 Y/ f
  14.         Create Red Packet* k$ x' y  m: z- L  O
  15.       </Button>
    1 R) |2 v- g3 q5 i$ o% {

  16. 0 w4 y3 c, q7 |0 f' o
  17.       <h3 style={{ marginTop: '1.5rem' }}>Available Red Packets</h3>
    % Q+ g5 m" k( U  b2 |
  18.       {redPackets.length === 0 ? (
    5 Z% {" x3 n1 d& q1 r0 B
  19.         <div>No Red Packets Available</div>
    % K, D+ Y5 T! g4 C& }0 P5 g
  20.       ) : (4 i* k: S) _4 I
  21.         <List>
    / q% m' j9 U. [. Z: h" x( _) x2 F* f
  22.           {redPackets.map((packet) => (! E2 m5 C; y  d
  23.             <div key={packet.id} className="packet-card"># }, Q7 p9 {: ]$ ^+ R
  24.               <div>
    ' o3 n0 g4 t- O8 C4 k; I* b2 G! ~) |
  25.                 <strong>Amount:</strong> {packet.amount}
    1 C0 d1 w* e4 }2 X! B5 l  W9 S
  26.               </div>+ L: K" ?/ m* b' }, j
  27.               <div>* @9 k7 n6 t4 \
  28.                 <strong>Quantity:</strong> {packet.quantity}
    + g+ o$ C  v6 U' d" H4 b4 q2 x
  29.               </div>5 |: n6 L' o, M2 i0 @7 I
  30.               <div>2 E6 |4 k/ O+ z  d
  31.                 <strong>Message:</strong> {packet.message}3 Z& f  T3 X8 Q
  32.               </div>
    7 _: ?, S% v1 @
  33.               <Button) B2 L. N3 h% M8 e
  34.                 size="small"
    0 W* q) e" e: }
  35.                 color="primary"% L4 S4 x3 P; h8 q( b
  36.                 onClick={() => navigate(`/claim/${packet.id}`)}9 _' u: l5 G0 _! i1 ^: V* D
  37.               >
    6 }5 Q* {. k, w& X8 T; t
  38.                 Claim* ]( G8 C# R" \
  39.               </Button>5 s" q" C2 P1 N4 V
  40.             </div>
    7 E5 L9 @. \9 o: w6 r3 A
  41.           ))}9 x/ e: \8 U6 \  L
  42.         </List>5 B; @) S+ E3 w% K# n
  43.       )}2 R  C( y! k3 m+ j* _! o  d
  44.     </div>( i# {9 F; p3 m; B' h# a% Y
  45.   );
    9 g7 U7 U5 l4 Z: B2 e: @6 E( B
  46. };0 z, L& v, r, Z" e8 A, X
  47. & W2 d" F/ n7 I6 s  ?: [
  48. export default HomePage;
复制代码
  1. import React, { useEffect } from 'react';2 h# F! g) d; A* d! Y
  2. import { TonConnectButton } from '@tonconnect/ui-react'; ( ~# j* s3 b& B& G3 b0 q% K
  3. import { Button } from 'antd-mobile';
      X8 S  f* U0 E  W: F/ O# m% E9 g) A
  4. import { useNavigate } from 'react-router-dom';
    7 Z- F, i* o. F* U  t9 I2 I
  5. import { useTonConnectModal, useTonAddress } from '@tonconnect/ui-react'; & @; G& w  ^# X+ f
  6. 4 a/ `: u, G% K2 y- l
  7. const LoginPage: React.FC = () => {
    4 l: _! F: g, e+ S
  8.   const navigate = useNavigate();
    ) }. J* q1 w& m+ C( c- A3 r
  9.   const { close } = useTonConnectModal();  . t+ A- \! a! N: ~
  10.   const address = useTonAddress();  6 w, H) H0 v1 Y8 V7 Q

  11. # g) O, P* g% i# I& y8 {
  12.   // Redirect to HomePage once connected
    % U! g( p6 |$ K4 m
  13.   useEffect(() => {' `4 B' B/ N$ `& R/ p5 J9 ~
  14.     if (address) {% W2 K3 O4 s5 V' _4 d; R
  15.       navigate('/');  // Navigate to HomePage when wallet is connected
    ) |1 B# g7 z  g5 i( h3 @
  16.     }# V8 j6 Y/ ]+ P$ P4 ?" q+ v
  17.   }, [address, navigate]);
    & z8 A( u1 f  G& |9 ]& ?

  18. . H1 }% A. o6 S' L
  19.   return (2 c4 l& i" o4 h* D+ U
  20.     <div style={{ padding: '1rem', textAlign: 'center' }}>
    ! H4 ]( A' K3 q$ b' p
  21.       <h2>Login to TON Wallet</h2>* P# M, n1 M6 l/ ?! Q, F! x

  22. + f+ W2 q. _+ U4 R- ]
  23.       {/* Show only TonConnectButton for connecting */}) ^! o" p+ l$ n" P( Y
  24.       <TonConnectButton style={{ marginBottom: '1rem' }} />
    2 y/ x1 ~( M7 P2 }2 K

  25. 1 H! _) N0 |. r( f
  26.       {/* Only show disconnect wallet button once connected */}
    ( x, i# g, `/ e8 F; F+ N$ {
  27.       {address && (
    $ @# x: N1 o: r: ]3 J
  28.         <>
    6 e# ^% ?) R$ b, a" ^4 w# U# ?
  29.           <p>Connected Wallet: {address}</p>' ~, i6 A! U% O
  30.           <Button onClick={() => close()}>Disconnect Wallet</Button>. Q1 s5 f3 m+ c9 D% J
  31.         </>* k3 C7 p' K; H
  32.       )}
    7 k; B5 b& r: f/ z# F- [0 s0 f

  33. " G  R$ G: f6 ^" @- b
  34.     </div>
    3 K" J  L) x9 J* w3 X
  35.   );
    8 U7 m/ {1 f, [7 S4 [
  36. };
    * N2 [/ ?2 |0 o& a# M
  37. , A1 M) [; H2 E8 U; t
  38. export default LoginPage;
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则