首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UseDapp - useCall -如何从实体函数中获得返回值?

UseDapp - useCall -如何从实体函数中获得返回值?
EN

Stack Overflow用户
提问于 2022-01-22 11:12:21
回答 4查看 1.3K关注 0票数 1

我还是很新的反应和坚定,不知道从哪里开始。我可以更新一个字符串,并希望在更改它之后打印出来。但我想要发条链上的绳子。返回值仍然是“未定义的”。

我的index.ts文件:

代码语言:javascript
复制
export function MyString(contract: Contract) {
    const { state, send } = useContractFunction(contract, "setString", {});
    return { state, send };
}

export function GetMyString(contract: Contract) {
    const { value, error } = useCall({
        contract: contract,
        method: 'getString',
        args: []
    }) ?? {};

    if (error) {
        console.log("Error: ", error.message);
        return undefined;
    }
    console.log("value", value);
    return value;
}

我的反应成分:

代码语言:javascript
复制
import React, { useState } from 'react';

import { useEthers } from "@usedapp/core";
import { ethers } from "ethers";
import myStringContractAbi from "./abi/myString.json";
import { myStringContractAddress } from "./contracts";
import { Contract } from "@ethersproject/contracts";

import { MyString, GetMyString } from "./hooks"

function App() {

  const { activateBrowserWallet, account, deactivate } = useEthers();

  const simpleContractInterface = new ethers.utils.Interface(myStringContractAbi);
  const contract = new Contract(myStringContractAddress, simpleContractInterface, ethers.getDefaultProvider(42));

  const { send, state } = MyString(contract);

  const value = GetMyString(contract);

  const [text, setText] = useState<string>("")
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const newText = event.target.value === "" ? "" : String(event.target.value)
    setText(newText)
  }

  const sendString = async () => {
     send(text);
  }

  const getContractString = async () => {
    console.log("APP VALUE", value);
    alert(value);
  }


  React.useEffect(() => {
    state.status === 'Exception' && console.log('State of set String: ', state.errorMessage);

    state.status === 'Success' && console.log('Set String successfully!');
  })

  return (
    <div>
      {!account && <button onClick={() => activateBrowserWallet()}> Connect </button>}
      {account && (
        <div>
          <button onClick={deactivate}>Disconnect</button>
        </div>
      )}
       <div>
          {account ? (
            <div>My Account Address: {account} </div>
          ) : (
            <div>Kein Account verbunden!</div>
          )}
        </div>

        <input onChange={handleChange} />
        <button onClick={sendString}>Call Function</button>

        <button onClick={getContractString}>Call Get String Function</button>
    </div>
  );
}

export default App;

这是我的合同:

代码语言:javascript
复制
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MyString {
    string public myString;

    constructor() {
        myString = "Not set yet";
    }

    function setString(string memory _myString) public {
        myString = _myString;
    }

    function getString() public view returns (string memory) {
        return myString;
    }
}

有人能帮我吗?你还需要其他信息吗?谢谢

EN

回答 4

Stack Overflow用户

发布于 2022-05-14 10:03:32

如果您想获得任何值,则不能使用useContractFunction。不要使用useCall,也不要使用ethers库。

示例useCall

代码语言:javascript
复制
import { useCall } from '@usedapp/core';
import { Contract } from '@ethersproject/contracts'; // comes with `@usedapp/core`
import {utils} from 'ethers';

const CONTRACT_ADDR = "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853";
const Interface = new utils.Interface(ABI); // ABI is array
const ContractInstance = new Contract(CONTRACT_ADDR, Interface);

// Custom contract payable function

const useTokenBalance = () => {
  const { value, error } = useCall({
    contract: ContractInstance,
    method: 'TokenBalance',
    args: [] /* params */
  });

  if(error) {
    return undefined
  }
  console.log("value", value);
  return value;
};

function App() {
  //...
  const TokenBalance  = useTokenBalance();

  const getTokenBalance = async () => {
   alert(TokenBalance);
  }
}

API文档:https://usedapp-docs.netlify.app/docs/api%20reference/hooks/#usecall

参见测试:https://github.com/TrueFiEng/useDApp/blob/17b80218e803395a16a29b94ef0b1b24931f50fb/packages/core/src/hooks/useCall.test.tsx

如何在ethers钩子框架中使用useDApp库;

代码语言:javascript
复制
import { useEthers } from '@usedapp/core';
import { Contract as CTR } from 'ethers';

const CONTRACT_ADDR = "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853";

function App() {
  //...
  const { account, library } = useEthers();

  const getTokenBalance = async () => {
    const signer = library.getSigner();
    const ctr = new CTR(CONTRACT_ADDR, ABI, signer);
    let tx = await ctr.TokenBalance(/* params */);
    alet(tx);
  }
}

API文档:https://docs.ethers.io/v5/api/contract/contract/#Contract--creating

测试版本;

  • ^5.6.5 ethers
  • ^1.0.2 @usedapp/core

更新

完整的源代码;

代码语言:javascript
复制
import './App.css';
import { useEthers, useContractFunction, useCall } from '@usedapp/core';
import {useState, useEffect, useCallback } from 'react';
import {utils, constants, BigNumber, Contract as CTR} from 'ethers';
import { Contract } from '@ethersproject/contracts'

const ENDPOINT = "http://127.0.0.1:4000";
const CONTRACT_ADDR = "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9";

const ABI = require('./Post.json').abi;
const Interface = new utils.Interface(ABI);
const Instance = new Contract(CONTRACT_ADDR, Interface);

const useAddMessage = () => {
  const { state, send, event } = useContractFunction(
    Instance,
    'addMessage',
    {}
  );
  return { state, send, event };
};

function App() {
  const { state: addMessageState, send: addMessage } = useAddMessage();

  const { activateBrowserWallet, account, library, chainId } = useEthers();

  const [ownerBalance, set_ownerBalance] = useState(0);
  const [contractInstance, set_contractInstance] = useState(null);

  const [msg, setMsg] = useState("");

  const [chainMsgs, setChainMsgs] = useState([]);

  // Error watching
  useEffect(() => {
    addMessageState.status === 'Exception' &&
      console.log('addMessageState: ', addMessageState.errorMessage);

    addMessageState.status === 'Success' &&
      console.log('Successfully added message to chain');
  }, [addMessageState]);

  useEffect(() => {
    if(account){

      library.getBalance(account).then(balance => {
        set_ownerBalance(utils.formatUnits(balance, "ether"));
      });

      set_contractInstance(new CTR(CONTRACT_ADDR, ABI, library.getSigner()));
    }
  }, [account]);
  
  const addMsg = async () => {
    if(msg.length > 0){
      let addedMessage = await addMessage(msg);
      // when below function correctly worked, that triggered `Error watching` statement
    }
  };

  const getMsg = async () => {
    let chainMessages = await contractInstance.getMessages({from: account});
    setChainMsgs(chainMessages);
  };

  return (
    <>
      <header>
        {
          !account &&
          <button onClick={() => activateBrowserWallet()} >Connect Wallet</button>
        }

        {
          account &&
          <>
            <div style={{display: 'flex'}}>
              <h1 id="msg-addr">{ellipseAddress(account, 5)}</h1>
              <span style={{margin: '0 0.5rem'}}>{ownerBalance} ETH</span>
            </div>
            <br />
          </>
        }
      </header>

      <main>
        {
          account &&
          <>
            <section>
              <input type={"text"} placeholder={"Leave trail"} value={msg} onChange={e => setMsg(e.target.value)} />
              <button onClick={async () => await addMsg()}>Add Message</button>
            </section>
            <section>
              <button onClick={async () => await getMsg()}>Get Message</button>
              {
                chainMsgs.length > 0 &&
                <ul>
                  {chainMsgs.map((chainMsg, i) => {
                    return (
                      <li key={i}>{chainMsg}</li>
                    )
                  })}
                </ul>
              }
              
            </section>
          </>
        }
        
      </main>
    </>
  );
}

function ellipseAddress(address='', width=10) {
  return !address ? '' : address.slice(0, width) + "..."  + address.slice(-width);
}

export default App;

正确检查来自package.json的软件包版本;

代码语言:javascript
复制
"dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "@usedapp/core": "^1.0.2",
    "ethers": "^5.6.5",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.0"
}
票数 2
EN

Stack Overflow用户

发布于 2022-01-22 11:49:02

这可能是因为您要传递给accountgetMessages(String(account))在可靠性方面与address类型不同。

实际上,要存储发件人的地址,您不必将帐户作为函数参数传递。Etherum已经将呼叫者地址检测为msg.sender

What is msg.sender

坚实的:

代码语言:javascript
复制
function getMessages() public view returns (string[] memory)
    {
        return messages[msg.sender];
    }

在react端,只需调用函数而不传递参数。

代码语言:javascript
复制
const handleLoad = () => {
        getMessages()
    }
票数 1
EN

Stack Overflow用户

发布于 2022-01-23 18:10:35

我建议您查看js中的有关承诺,但是要查看应该等待的返回值,则需要使用较长的历史时间--这可以这样做-- const {state, send} = await useContractFunction(...),但是为了使用“等待”关键字,使用它的函数应该有关键字async (postContract: Contract) =>,请记住,对块链的所有读写都使用承诺。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70812225

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档