英文:
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 "./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.
答案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("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);
});
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论