{"content":{"title":"【Sui】 前端共学笔记(3)","body":"![88f9d4b7250a724489ed6e23ff6ea7f.jpg](https://img.learnblockchain.cn/attachments/2025/01/zDGMnQL26788ea1ea25b3.jpg)\r\n请关注 **sui** 前端共学营及其社区，在这里你可以学到前端和 **move** 合约语言的知识。\r\nDapp，Next.js 与合约的交互\r\n## 项目搭建\r\n使用`npx create-nextjs-sui-dapp-template`搭建nextjs框架的suiDapp（我这里使用的是测试网）然后安装依赖后使用`npm run dev`启动项目。\r\n## 网络合约设置\r\n进入文件`contracts/index.ts`\r\n```js\r\n    testnet: {\r\n        url: getFullnodeUrl(\"testnet\"),\r\n        variables: {\r\n            package: \"youPackageID\",\r\n            state: \"youObjectID\",\r\n        }\r\n    },\r\n```\r\n以这样的形式设置合约和对象。\r\n## 合约调用\r\n我这里使用的是3讲_2视频中的demo合约：\r\n```move\r\n    module demo::demo;\r\n    public struct State has key, store {\r\n        id: UID,\r\n        acount: u64,\r\n    }\r\n\r\n    fun init (ctx: &mut TxContext) {\r\n        let state = State {\r\n            id: object::new(ctx),\r\n            acount: 0,\r\n        };\r\n        transfer::public_share_object(state);\r\n    }\r\n\r\n    public entry fun deposit (state: &mut State, amount: u64) {\r\n        state.acount = state.acount + amount;\r\n    }\r\n```\r\n他是一个简单的对object内数值进行累加的合约，我们在`contracts`文件下创建一个同名ts文件来对合约调用：\r\n ```ts\r\n import { createBetterTxFactory } from \".\";\r\n\r\nexport const deposit = createBetterTxFactory<{amount:number}>((tx, networkVariables, params) => {\r\n    tx.moveCall({\r\n        package: networkVariables.package,\r\n        module: \"demo\",\r\n        function: \"deposit\",\r\n        arguments: [\r\n            tx.object(networkVariables.state),\r\n            tx.pure.u64(params.amount),\r\n        ],\r\n    })\r\n    return tx;\r\n})\r\n ```\r\n这段代码是用来创建一个交易函数（`deposit`），并通过 `createBetterTxFactory` 包装它，从而简化与 Sui 区块链的交互。\r\n### 1. `createBetterTxFactory<{amount:number}>`\r\n* `createBetterTxFactory` 是一个用于创建交易的工厂函数，用来生成具有特定结构和行为的事务。`<{amount: number}>` 表明这是一个带有 `amount` 参数的函数。\r\n\r\n### 2. `tx.moveCall`\r\n* `tx.moveCall` 用于调用一个 Move 合约函数。在这里，它调用的是名为 `deposit` 的 Move 合约函数。`moveCall` 是一种交易类型，用于在 Sui 区块链上执行 Move 程序。\r\n\r\n### 3. `tx.object(networkVariables.state)`\r\n* 这行代码指定了交易中所需的 Sui 对象。`networkVariables.state` 一个对象，它会作为参数传递到 Move 合约函数中。\r\n\r\n### 4. `tx.pure.u64(params.amount)`\r\n* `tx.pure.u64(params.amount)` 将 `amount` 参数转换为一个纯数据值，并指定其类型为 `u64`（64位无符号整数）。\r\n* 这意味着 `amount` 是以 64 位整数的形式传递到 Move 合约中。\r\n\r\n### 5. `return tx`\r\n* 返回处理后的 `tx` 对象，表示构建好的交易。\r\n\r\n## context\r\ncontext用于组件之间共享和管理状态，当需要在应用中访问和共享“用户数据”时，就可以用`context` 来实现。我们在创建一个文件`context`下面用来实现context：\r\n(这里有一个getState的方法写在了`contracts/query.ts`中下面有)\r\n```js\r\nimport { getState } from \"../contracts/query\"\r\nimport { useState, useCallback, useContext, createContext } from \"react\"\r\n\r\n\r\ninterface StateContextType {\r\n    acount: number\r\n    refresh:()=>Promise<void>\r\n}\r\n\r\nconst StateContext = createContext<StateContextType | undefined>(undefined)\r\n\r\ninterface StateProviderProps {\r\n    children: React.ReactNode\r\n}\r\n\r\nexport const StateProvider: React.FC<StateProviderProps> = ({ children }) => {\r\n    const [acount, setAccount] = useState<number>(0)\r\n    const refresh = useCallback(async () => {\r\n        const state = await getState()\r\n        const data = state.data?.content as unknown as {fields: {acount: number}}\r\n        const acount = data.fields.acount\r\n        setAccount(acount)\r\n    }, [])\r\n\r\n    return (\r\n        <StateContext.Provider value={{ acount, refresh }}>{children}</StateContext.Provider>\r\n    )\r\n}\r\n\r\nexport function useStateContext() {\r\n    const context = useContext(StateContext)\r\n    if (!context) {\r\n        throw new Error(\"useContext must be used within a StateProvider\")\r\n    }\r\n    return context\r\n}\r\n```\r\n这段代码用于共享和管理应用中的`acount`。它通过创建一个 `StateContext` 和提供一个 `StateProvider` 组件，使得应用中的其他组件能够访问和更新这个状态。这个 `StateContext` 主要用于存储和更新 `acount`，并提供了一个 `refresh` 方法来刷新该值。\r\n注意之后要将这里的`</StateProvider>`使用在`app/providers`中\r\n```ts\r\nexport function Providers({ children }: { children: React.ReactNode }) {\r\n  return (\r\n    <QueryClientProvider client={queryClient}>\r\n      <SuiClientProvider networks={networkConfig} defaultNetwork={network}>\r\n        <WalletProvider>\r\n          <StateProvider>\r\n            {children}\r\n          </StateProvider>\r\n        </WalletProvider>\r\n      </SuiClientProvider>\r\n    </QueryClientProvider>\r\n  );\r\n}\r\n```\r\n getState()\r\n```ts\r\nexport const getState = async ()=>{\r\n  const state = await suiClient.getObject({\r\n    id: networkConfig[network].variables.state,\r\n    options: {\r\n      showContent: true,\r\n    },\r\n  });\r\n  return state;\r\n}\r\n```\r\n## page页面调用\r\n使用 `useBetterSignAndExecuteTransaction` 自定义 hook 来执行一个交易（`deposit`），并获取一个 `handleSignAndExecuteTransaction` 函数，用于处理交易签名和执行。\r\n```js\r\n  const { handleSignAndExecuteTransaction: depositHandler } = useBetterSignAndExecuteTransaction({\r\n    tx: deposit,\r\n  });\r\n```\r\n还需要而外加一个hook去使用context的内容\r\n```js\r\n  const {acount, refresh} = useStateContext();\r\n```\r\n下面是完整调用：\r\n```ts\r\n  const account = useCurrentAccount();\r\n  const [userObjects, setUserObjects] = useState<CategorizedObjects | null>(null);\r\n  const { handleSignAndExecuteTransaction: depositHandler } = useBetterSignAndExecuteTransaction({\r\n    tx: deposit,\r\n  });\r\n  const {acount, refresh} = useStateContext();\r\n\r\n  const handleIncrement = async () => {\r\n    await depositHandler({ amount: 1}).onSuccess(async () => {\r\n      await refresh();\r\n      console.log('onSuccess')\r\n    }).onError(async (error) => {\r\n      console.log('onError', error)\r\n    }).execute()\r\n  }\r\n\r\n  useEffect(() => {\r\n    async function fetchUserProfile() {\r\n      if (account?.address) {\r\n        try {\r\n          const profile = await getUserProfile(account.address);\r\n          await refresh();\r\n          setUserObjects(profile);\r\n        } catch (error) {\r\n          console.error('Error fetching user profile:', error);\r\n        }\r\n      }\r\n    }\r\n    console.log(acount);\r\n    fetchUserProfile();\r\n  }, [account, refresh, acount]);\r\n \r\n return(\r\n     <button onClick={ handleIncrement} >Increment</button>\r\n )\r\n}\r\n```"},"author":{"user":"https://learnblockchain.cn/people/23988","address":null},"history":"bafkreidrayb2zmlbc6kmaynjqilr5cspxwr7zohx6qnezljeaiqni4ijom","timestamp":1737202240,"version":1}