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 "./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;
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.
CodePudding user response:
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("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);
});
}