点击两次后状态改变,useEffect也不起作用。

huangapple go评论59阅读模式
英文:

State changes after 2 clicks and useEffect also not working

问题

我有一个基本的React网站模板,其中有一个按钮,可以连接到你的Metamask钱包并显示当前余额。

我遇到了一个经典问题,即“addressBalance”状态只有在第二次点击连接钱包按钮后才变得可见。(基本上,我需要点击两次才能显示“addressBalance”状态的更改。)

我添加了一个useEffect钩子,它在“addressBalance”状态发生变化时触发,但是这个useEffect也只在页面加载后和第二次点击后触发。

这是我的代码:

import "./App.css";
import { useState, useEffect } from "react";
import { ethers } from "ethers";

function App() {
  const [walletAddress, setWalletAddress] = useState("");
  const [addressBalance, setaddressBalance] = useState("");

  useEffect(() => {
    console.log("Balance updated:", addressBalance);
  }, [addressBalance]);

  async function requestAccount() {
    console.log("Requesting account...");

    if (window.ethereum) {
      console.log("detected");

      try {
        const accounts = await window.ethereum.request({
          method: "eth_requestAccounts",
        });

        setWalletAddress(accounts[0]);
        getBalance();
      } catch (error) {
        console.log("Error connecting...");
      }
    } else {
      alert("Meta Mask not detected");
    }
  }

  function getBalance() {
    const result = window.ethereum
      .request({
        method: "eth_getBalance",
        params: [walletAddress, "latest"],
      })
      .then((result) => {
        console.log(result);
        let wei = parseInt(result, 16);
        let balance = wei / 10 ** 18;
        setaddressBalance(balance);
      });
  }

  async function connectWallet() {
    if (typeof window.ethereum !== "undefined") {
      await requestAccount();

      const provider = new ethers.providers.Web3Provider(window.ethereum);
    }
  }

  return (
    <div className="App">
      <header className="App-header">
        <button className="request-account" onClick={requestAccount}>
          Request Account
        </button>
        <h3>Wallet Address: {walletAddress}</h3>
        <h3>
          {!walletAddress
            ? "No address connected..."
            : `Balance: ${addressBalance} ETH`}
        </h3>
      </header>
    </div>
  );
}

export default App;

我想知道为什么useEffect钩子在第一次点击后没有触发,以及如何解决这个问题。

英文:

I have a basic template of a react website with a button that connects to your metamask wallet and displays the current balance.

I have the classic issue that the state of 'addressBalance' only becomes visible after the second click on the connect wallet button. (Basically: I need to click 2 times to show the changes of the 'addressBalance' state.)

I added a useEffect hook that gets triggered whenever 'addressBalance' state changes however the useEffect also only gets triggered on loading the page & after the second click.

This is my code:

import &quot;./App.css&quot;;
import { useState, useEffect } from &quot;react&quot;;
import { ethers } from &quot;ethers&quot;;
function App() {
const [walletAddress, setWalletAddress] = useState(&quot;&quot;);
const [addressBalance, setaddressBalance] = useState(&quot;&quot;);
useEffect(() =&gt; {
console.log(&quot;Balance updated:&quot;, addressBalance);
}, [addressBalance]);
async function requestAccount() {
console.log(&quot;Requesting account...&quot;);
if (window.ethereum) {
console.log(&quot;detected&quot;);
try {
const accounts = await window.ethereum.request({
method: &quot;eth_requestAccounts&quot;,
});
setWalletAddress(accounts[0]);
getBalance();
} catch (error) {
console.log(&quot;Error connecting...&quot;);
}
} else {
alert(&quot;Meta Mask not detected&quot;);
}
}
function getBalance() {
const result = window.ethereum
.request({
method: &quot;eth_getBalance&quot;,
params: [walletAddress, &quot;latest&quot;],
})
.then((result) =&gt; {
console.log(result);
let wei = parseInt(result, 16);
let balance = wei / 10 ** 18;
setaddressBalance(balance);
});
}
async function connectWallet() {
if (typeof window.ethereum !== &quot;undefined&quot;) {
await requestAccount();
const provider = new ethers.providers.Web3Provider(window.ethereum);
}
}
return (
&lt;div className=&quot;App&quot;&gt;
&lt;header className=&quot;App-header&quot;&gt;
&lt;button className=&quot;request-account&quot; onClick={requestAccount}&gt;
Request Account
&lt;/button&gt;
&lt;h3&gt;Wallet Address: {walletAddress}&lt;/h3&gt;
&lt;h3&gt;
{!walletAddress
? &quot;No address connected...&quot;
: `Balance: ${addressBalance} ETH`}
&lt;/h3&gt;
&lt;/header&gt;
&lt;/div&gt;
);
}
export default App;

I'd like to know how it is possible that the useEffect hook isn't triggered after the first click and how I can fix this problem.

答案1

得分: 1

你的useEffect钩子在第一次点击时没有触发,这是因为当你调用setWalletAddress时,你的getBalance函数立即尝试访问walletAddress的值,但由于React的“异步”状态更新行为,walletAddress变量在你调用getBalance()时还没有被更新为accounts[0]

修复这个问题的一种简单方法是将钱包地址作为显式参数传递给getBalance函数:

async function requestAccount() {
  console.log("Requesting account...");

  if (window.ethereum) {
    console.log("detected");

    try {
      const accounts = await window.ethereum.request({
        method: "eth_requestAccounts",
      });

      setWalletAddress(accounts[0]);
      getBalance(accounts[0]);
    } catch (error) {
      console.log("Error connecting...");
    }
  } else {
    alert("Meta Mask not detected");
  }
}

function getBalance(walletAddress) {
  const result = window.ethereum
    .request({
      method: "eth_getBalance",
      params: [walletAddress, "latest"],
    })
    .then((result) => {
      console.log(result);
      let wei = parseInt(result, 16);
      let balance = wei / 10 ** 18;
      setaddressBalance(balance);
    });
}
英文:

Your useEffect hook isn't getting triggered on the first click because when you call setWalletAddress, your getBalance function immediately tries to access the value of walletAddress but because of React's "asynchronous" state update behavior, the walletAddress variable hasn't been updated to accounts[0] by the time you've called getBalance().

An easy way to fix this is to pass the wallet address as an explicit parameter to getBalance:

 async function requestAccount() {
console.log(&quot;Requesting account...&quot;);
if (window.ethereum) {
console.log(&quot;detected&quot;);
try {
const accounts = await window.ethereum.request({
method: &quot;eth_requestAccounts&quot;,
});
setWalletAddress(accounts[0]);
getBalance(accounts[0]);
} catch (error) {
console.log(&quot;Error connecting...&quot;);
}
} else {
alert(&quot;Meta Mask not detected&quot;);
}
}
function getBalance(walletAddress) {
const result = window.ethereum
.request({
method: &quot;eth_getBalance&quot;,
params: [walletAddress, &quot;latest&quot;],
})
.then((result) =&gt; {
console.log(result);
let wei = parseInt(result, 16);
let balance = wei / 10 ** 18;
setaddressBalance(balance);
});
}

huangapple
  • 本文由 发表于 2023年1月8日 22:43:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75048665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定