1. 处理事务生命周期

1.1. 这为什么重要?

与智能合约交互时最薄弱的环节在于交易发送速度以及等待节点返回结果的时间。这一特性对用户体验(UX)有着重大影响。交易可能会遇到错误、回滚、Gas不足等问题,因此在设计用户界面时,必须妥善处理整个交易生命周期,以便用户能够清晰地了解当前状态。

1.2. Wagmi 提供哪些服务?

Wagmi 中的 React Hooks 提供了许多功能,可帮助您管理事务生命周期。例如:

useReadContract

Wagmi的 useReadContract 在调用时,hook 会返回数据 函数 不作任何更改 状态此外,该回调函数还会返回一个状态对象(例如 错误, 待处理) 以便向用户显示相应的交易状态。

// import BaseError and hook useReadContract
import { type BaseError, useReadContract } from 'wagmi'
// import the smart contract's abi file to get the function's interface
import { abi } from './abi'

function ReadContract() {
  const { 
    data: balance, // assign the returned data to the balance variable
    error, // initialize error variable
    isPending // initialize the isPending variable
  } = useReadContract({
    abi, // abi của function
    functionName: 'balanceOf', // function name you want to call
    args: ['0x03A71968491d55603FFe1b11A9e23eF013f75bCF'], // Pass variables to the function
  })
  
  // If isPending is true, the text "Loading..." is displayed, otherwise it disappears
  if (isPending) return <div>Loading...</div> 
  
  // If there is an error, display the div with error message
  if (error) 
    return ( 
      <div>
        Error: {(error as BaseError).shortMessage || error.message} 
      </div> 
    )  

  return (
    // Displays the balance (if any) after converting to string format
    <div>Balance: {balance?.toString()}</div>
  )
}

useWriteContract

Wagmi的 useWriteContract hook 返回一个 数据 包含该 哈希 在调用一个 函数 这会改变 状态 智能合约的。

数据
`WriteContractReturnType | undefined`

默认值为 `undefined`
最后一个成功解析的数据 用于

此外,该回调函数还会返回一个 待处理 一个可用于显示事务待处理状态的对象。

此外,Wagmi 还提供 useWaitForTransactionReceipt 一个用于等待事务结果的回调函数,带有 2 个返回变量: 正在加载, isSuccess.

以下是来自 Wagmi v2 文档的一个示例:

import * as React from 'react' // import react into file
// import BaseError, and 2 hooks useWaitForTransactionReceipt, useWriteContract from wagmi library
import { 
  type BaseError, 
  useWaitForTransactionReceipt, 
  useWriteContract 
} from 'wagmi'
// import the smart contract's abi file to get the function's interface
import { abi } from './abi'
 
export function MintNFT() {
  const { 
    data: hash, // assign the returned data to a variable named hash
    error, // assign error object to error variable
    isPending, // assign the isPending object to the isPending variable
    writeContract // initialize the writeContract function for use
  } = useWriteContract() 

  // function dùng để submit form
  async function submit(e: React.FormEvent<HTMLFormElement>) { 
    e.preventDefault() 
    const formData = new FormData(e.target as HTMLFormElement) 
    const tokenId = formData.get('tokenId') as string 
    writeContract({
      address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // contract address
      abi, // abi of contract
      functionName: 'mint', // function name you want to call
      args: [BigInt(tokenId)], // pass input to function
    })
  } 

  // Call the useWaitForTransactionReceipt hook to initialize the isConfirming and isConfirmed states
  const { isLoading: isConfirming, isSuccess: isConfirmed } = 
    useWaitForTransactionReceipt({ 
      hash, 
    }) 

  // Return format of React
  return (
    <form onSubmit={submit}>
      <input name="address" placeholder="0xA0Cf…251e" required />
      <input name="value" placeholder="0.05" required />
      // If isPending is true, the button will be disabled
      <button 
        disabled={isPending} 
        type="submit"
      >
        {isPending ? 'Confirming...' : 'Mint'} 
        // If isPending is true, display the word "Confirming...", otherwise display the word "Mint"
      </button>
      // If hash is true, the div containing the transaction hash is displayed, otherwise it disappears
      {hash && <div>Transaction Hash: {hash}</div>}
      // If isConfirming is true then display the div with the text "Waiting for confirmation..."
      {isConfirming && <div>Waiting for confirmation...</div>} 
      // If isConfirmed is true, display the div with the text "Transaction confirmed."
      {isConfirmed && <div>Transaction confirmed.</div>}
      // If there is an error, display the div with error message
      {error && ( 
        <div>Error: {(error as BaseError).shortMessage || error.message}</div> 
      )} 
    </form>
  )
}