【问题标题】:How to detect transaction confirmation with web3.js and re-render with React如何使用 web3.js 检测交易确认并使用 React 重新渲染
【发布时间】:2022-11-11 07:24:00
【问题描述】:

上下文:该应用程序是一个简单的链上待办事项列表,可让您查看待办事项列表并创建新的待办事项。

问题:当我创建新的待办事项并使用createTask() 将其发送到链上时,我正在努力检查交易确认,然后我可以重新渲染待办事项列表以显示新提交的输入并在链上确认。

技术栈:Web3.js + React

供您参考:我一直在关注本教程:https://www.dappuniversity.com/articles/ethereum-dapp-react-tutorial

import './App.css';
import Web3 from 'web3'
import { useEffect, useState } from 'react'

import { TODOLIST_ABI, TODOLIST_ADDRESS } from './config'
import Tasks from './Tasks'
import CreateTasks from './CreateTasks'

const App = () => {
  const [acct, setAcct] = useState('')
  const [contract, setContract] = useState([])
  const [task, setTask] = useState([])
  const [taskCount, setTaskCount] = useState(0)
  const [loading, setLoading] = useState(false)

  const loadBlockchainData = async () => {
    setLoading(true)
    const provider = window.ethereum
    try {
      const web3 = await new Web3(provider)
      const acc = await (await web3.eth.requestAccounts())[0]
      setAcct(acc)

      const todo_list = new web3.eth.Contract(TODOLIST_ABI, TODOLIST_ADDRESS)
      setContract(todo_list)

      const taskCount = await todo_list.methods.taskCount().call()
        
      setTaskCount(taskCount)
      for (var i = 1; i <= taskCount; i++) {
        // methods.mymethod.call - call constant method sithout sending any transaction
        const temp_task = await todo_list.methods.tasks(i).call()
        setTask(t => {return [...t, temp_task]})
      }
      setLoading(false) 

    } catch (error) {
      console.log(`Load Blockchain Data Error: ${error}`)
    } 
  }
  

  const loadTasks = async () => {

    const taskCount = await contract.methods.taskCount().call()
    
    setTaskCount(taskCount)
    setTask(() => [])
    for (var i = 1; i <= taskCount; i++) {
      // methods.mymethod.call - call constant method sithout sending any transaction
      const temp_task = await contract.methods.tasks(i).call()
      setTask(t => {return [...t, temp_task]})
    }
  }

  const createTask = async (text) => {

    setLoading(true)
    console.log(`onsubmit: ${text}`)
    await contract.methods.createTask(text).send({from: acct}).once('sent', r => {
      console.log(`Transaction Hash: ${r['transactionHash']}`)
      loadTasks()
    })
    setLoading(false)
  }

  useEffect(() => {
    loadBlockchainData()
  }, [])

  return (
    <>
      <h1>Hello</h1>
      <p>Your account: { acct }</p>
      {loading? (<p>loading...</p>) : (<Tasks task={ task }/>)}
      <CreateTasks contract={ contract } account={ acct } createTask={ createTask }/>
    </>
  )

}

export default App;

【问题讨论】:

    标签: javascript reactjs ethereum web3js web3-react


    【解决方案1】:
      const taskCount = await todo_list.methods.taskCount().call()
    

    如果是 taskCount=undefined,最好在 if 语句中运行 for-loop

     if(taskCount){//for-loop here}
    

    由于您按顺序多次调用合约方法,因此您每次都会得到承诺,其中一个承诺可能会被拒绝。想象一下你的 taskCount 是 10 的场景,但是当 i=5 你的承诺被拒绝并且你退出循环并且 catch 块运行时。在这种情况下,您将只捕获以前的任务。为了防止这种情况,您应该实现所有已解决的承诺或没有解决。 (原子事务)

    在这种情况下,您应该使用Promise.all

    if(taskCount){
        Promise.all(
          // because taskCount is string.convert it to number
          Array(parseInt(taskCount))
            .fill() // if taskCount=2, so far we got [undefined,undefined]
            .map((element,index)=>{
                const temp_task = await todo_list.methods.tasks(index).call()
                setTask(t => {return [...t, temp_task]})
                
        })
    )
    

    }

    【讨论】:

      猜你喜欢
      • 2020-06-08
      • 2023-02-12
      • 2022-09-22
      • 2021-12-29
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-22
      相关资源
      最近更新 更多