1. Quản trị vòng đời của transaction
1.1. Tại sao phải chú trọng
Điểm yếu nhất của việc tương tác với smart contract là tốc độ gửi giao dịch và chờ kết quả từ node trả về. Đây là đặc điểm gây ảnh hưởng nặng nề đến trải nghiệm (UX) của người dùng. Các giao dịch có thể gặp các vấn đề như là bị lỗi, revert, thiếu gas, v.v... nên khi thiết kế giao diện của người dùng, chúng ta phải chăm chút vào xử lý toàn bộ vòng đời của giao dịch để người dùng biết được rõ nhất trạng thái hiện tại.
1.2. Wagmi hỗ trợ gì?
Các React Hook trong Wagmi có rất nhiều tính năng để giúp bạn quản trị vòng đời của transaction. Ví dụ như:
useReadContract
Hook useReadContract
của Wagmi trả về cho chúng ta dữ liệu khi gọi function
không thay đổi state
. Ngoài ra, hook cũng trả về status object (ví dụ như error
, isPending
) để chúng ta có thể hiển thị cho người dùng trạng thái giao dịch tương ứng.
// 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
Hook useWriteContract
của Wagmi trả về cho chúng ta object data
có chứa hash
của giao dịch sau khi gọi một function
thay đổi state
của smart contract.
data
`WriteContractReturnType | undefined`
Defaults to `undefined`
The last successfully resolved data for the mutation.
Ngoài ra, hook còn trả về cho chúng ta object isPending
để chúng ta có thể sử đụng để hiển thị trạng thái chờ cho giao dịch.
Thêm nữa, Wagmi còn cung cấp thêm useWaitForTransactionReceipt
hook để chúng ta chờ kết quả giao dịch với 2 biến trả về là isLoading
, isSuccess
.
Dưới đây là một ví dụ từ Wagmi v2 docs:
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>
)
}