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