在Context生成需要await的合约,拿到的是null

163 阅读1分钟

一开始在context里面是这样写的

  
  const [reporterToken, setReporterToken] = useState(null);
  //...
  
  let reporterTokenTemp;

  const generateReporterToken = async () => {
    try {
      const reportertoken_addr = await token.getConditionalTokens();

      reporterTokenTemp = new ethers.Contract(
        reportertoken_addr,
        new Interface(conditionalToken_abi),
        provider.getSigner()
      );

      setReporterToken(reporterTokenTemp);
    } catch (error) {
      console.error("generateReporterToken error", error);
    }
  };

  useEffect(() => {
    if (token?.provider) {
      generateReporterToken();
    }
  }, [token?.provider]);

  return (
    <Web3Context.Provider
      value={{
        contracts: {
        //..
          reporterToken: reporterToken,
        },
      
      }}
    >
      {children}
    </Web3Context.Provider>
  );

然后在要用到reporterToken合约的地方用useWeb3Context去拿到reporterToken的时候一开始总是拿到null,这是因为const [reporterToken, setReporterToken] = useState(null); 的初始值是null 等reporterToken合约生成好后,context不会实时更新。所以我尝试了:

尝试1:给reporterToken单独生成一个context ,因为reporterToken是依赖token合约的,所以新的context得在Web3Context下面,才能拿到token合约

尝试2:因为context不能实时更新数据,就用useDispatch去更新,但是因为在按原本的代码,生成合约是在异步函数里面,不能调用useDispatch

const generateReporterToken = async () => {
//不能在这里调用hook 
}

如果把函数改成自定义hook:

const useReporterToken = async ({ token, provider }) => {
  const reportertoken_addr = await token.getConditionalTokens();
  let reporterToken = new ethers.Contract(
    reportertoken_addr,
    new Interface(conditionalToken_abi),
    provider.getSigner()
  );
    useDispatch({reporterToken};//那就可以用useDispatch
};

但是既然改成自定义hook,为什么不直接拿到返回值呢

const useReporterToken = async ({ token, provider }) => {
  const reportertoken_addr = await token.getConditionalTokens();
  let reporterToken = new ethers.Contract(
    reportertoken_addr,
    new Interface(conditionalToken_abi),
    provider.getSigner()
  );
  return reporterToken;
};

这样子在使用的时候 又得包裹一层async await

所以最终的解决方案是在使用到reporterToken 合约的地方直接生成,当然也可以采用尝试1,但是那样代码量会多一些

useEffect(() => {
    (async () => {
      try {
       //直接生成合约
        const reportertoken_addr = await token.getConditionalTokens();
        let reporterToken = new ethers.Contract(
          reportertoken_addr,
          new Interface(conditionalToken_abi),
          provider.getSigner()
        );
        //使用到reporterToken 合约的地方:
        let conditionID = await reporterToken?.getConditionId(
        //..