React 路由组件多次调用函数
Posted
技术标签:
【中文标题】React 路由组件多次调用函数【英文标题】:React router component calls function multiple times 【发布时间】:2021-11-22 17:41:13 【问题描述】:我正在尝试学习区块链开发,所以几周前我开始学习 Solidity,我不得不为我与 React 签订的合同创建一个前端应用程序,我也不知道。
所以,我已经阅读了文档并观看了使用 web3 库和一些页面转换的教程。现在我可以在应用程序的页面之间导航,但是当我路由到特定页面时,我的函数会被多次调用。
这是我每次运行应用程序时都会加载的 index.js。我已经这样设置了路线。
index.js(我没有 app.js 和 app.js 一样使用 index.js)
import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';
import Web3 from 'web3'
import ConnectPage from './ConnectPage';
import MintPage from './MintPage';
import AllCryptonauts from './AllCryptonauts';
import MyCryptonauts from './MyCryptonauts';
import NotFound from './NotFound';
import BrowserRouter, Route, Switch from 'react-router-dom'
function App()
if (window.ethereum)
window.web3 = new Web3(window.ethereum)
window.ethereum.enable()
else
alert("Could not detect MetaMask. Please install MetaMask before proceeding!");
return (
<div>
<Switch>
<Route exact path="/" component=ConnectPage />
<Route exact path="/MintPage" component=MintPage />
<Route exact path="/MyCryptonauts" component=MyCryptonauts />
<Route exact path="/AllCryptonauts" component=AllCryptonauts />
<Route path="*" component=NotFound />
</Switch>
</div>
);
ReactDOM.render(
<React.StrictMode>
<BrowserRouter><App /></BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
我在第一页创建了一个连接按钮,它将我重定向到薄荷部分。
ConnectPage.js
import React from 'react'
export const ConnectPage = (props) =>
async function Connect()
const web3 = window.web3
const networkId = await web3.eth.net.getId()
if (networkId === 4)
props.history.push("/MintPage")
else
await window.ethereum.request(
method: 'wallet_switchEthereumChain',
params: [ chainId: '0x4' ],
);
props.history.push("/MintPage")
return (
<div>
<div style= display: 'flex', justifyContent: 'center', alignItems: 'center' ><img src="https://nftornek.000webhostapp.com/frontend/cnlogo.png"></img></div>
<div style= display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: '5%'><button className="connectButton" onClick=Connect>Enter the Universe</button></div>
</div>
)
这是我进行铸币交易的地方。我放了 console.log(" called checkChainID") 来查看 checkChainID 函数被调用了多少次。每次加载页面时它会被调用 12 次,在我尝试导航到同一页面后会调用两次。
作为所有这些的初学者,我收集了我从教程中获得的信息,这些信息并不明显,并尝试制作一个带有路由的测试应用程序(我也通过教程制作了它)
路由就像我在教程中所做的一样工作,我想继续为我的应用程序使用这个路由示例,但可能由于我缺乏 React 的基本知识,我在页面中做错了。我一直在研究这个问题几个小时,但无法真正理解我能做些什么来解决它。
我认为这是因为 useState,因为它每次调用它时都会呈现应用程序,但我不确定是否有任何方法可以防止这种情况发生,或者想出更聪明的方法。
MintPage.js
import React, useState from 'react';
import Web3 from 'web3'
import Contract from "../src/build/Contract.json";
export const MintPage = (props) =>
const web3 = window.web3;
var [currentAccount, setCurrentAccount] = useState("0x0");
var [currentBalance, setCurrentBalance] = useState("0");
var [mintAmount, setMintAmount] = useState(1);
const [addAmount, setAddAmount] = useState(true);
const [subtractAmount, setSubtractAmount] = useState(false);
window.ethereum.on('chainChanged', (_chainId) => checkChainID());
window.ethereum.on('accountsChanged', (_accounts) => loadBlockchainData());
checkChainID();
async function checkChainID()
const networkId = await web3.eth.net.getId();
if (networkId !== 4)
props.history.push("/")
else
loadBlockchainData();
console.log("called checkChainID")
async function loadBlockchainData()
window.web3 = new Web3(window.ethereum);
const accounts = await web3.eth.getAccounts();
setCurrentAccount(accounts[0]);
getBalance(accounts[0]);
async function getBalance(acc)
const balance = await web3.eth.getBalance(acc);
var balanceEth = web3.utils.fromWei(balance, 'ether');
setCurrentBalance(parseFloat(balanceEth).toFixed(3) + " ETH");
const SmartContractObj = new web3.eth.Contract(Contract.abi, "0x187FF2d65dd7204f11ea0487F2EED36378946902");
function MintPage()
props.history.push("/MintPage")
function MyCryptonauts()
props.history.push("/MyCryptonauts")
function AllCryptonauts()
props.history.push("/AllCryptonauts")
function Disconnect()
props.history.push("/")
return (
<div>
<div style= display: 'flex', justifyContent: 'center', alignItems: 'center' ><img src="https://nftornek.000webhostapp.com/frontend/cnlogo.png" width='500' height='180'></img></div>
<div style= display: 'flex', justifyContent: 'center' >
<button className="regularButton divide" onClick=MintPage>Mint</button>
<button className="regularButton divide" onClick=MyCryptonauts>My Cryptonauts</button>
<button className="regularButton divide" onClick=AllCryptonauts>All Cryptonauts</button>
<button className="regularButton divide" onClick=Disconnect>Disconnect</button>
</div>
<div style= display: 'flex', justifyContent: 'center' ><p className="accountText">Current Account: currentAccount</p></div>
<div style= marginTop: '25%' ></div>
<div style= display: 'flex', justifyContent: 'center' ><p className="accountText">Mint mintAmount Cryptonaut for XXX ETH</p></div>
<div style= display: 'flex', justifyContent: 'center' ><button className="amountButton divide" disabled=subtractAmount ? 0 : 1 onClick=() =>
if (mintAmount <= 1)
setMintAmount(1);
setSubtractAmount(false);
else
setMintAmount(mintAmount - 1);
if (mintAmount === 2)
setSubtractAmount(false);
if (mintAmount >= 1)
setAddAmount(true);
>-
</button>
<button className="mintButton divide" onClick=() =>
console.log(mintAmount);
>MINT
</button>
<button className="amountButton divide" disabled=addAmount ? 0 : 1 onClick=() =>
if (mintAmount >= 5)
setMintAmount(5);
else
setMintAmount(mintAmount + 1);
if (mintAmount === 4)
setAddAmount(false);
if (mintAmount >= 1)
setSubtractAmount(true);
>+
</button>
</div>
<div style= display: 'flex', justifyContent: 'center', marginTop: '7px' ><p className="accountText">Current Balance: currentBalance</p></div>
</div>
)
我将非常感谢任何帮助。请指出我正确的方向!不过,可能需要更多详细的解释,因为我对此太陌生了。 :) 谢谢大家。
【问题讨论】:
【参考方案1】:有问题的部分是这三行:
window.ethereum.on('chainChanged', (_chainId) => checkChainID());
window.ethereum.on('accountsChanged', (_accounts) => loadBlockchainData());
checkChainID();
您通常不希望在组件的渲染周期中直接调用函数,因为组件可能会出于多种不同的原因重新渲染。每次此组件呈现时,它都会向全局 ethereum
对象添加一个事件侦听器,因此您将在每个组件呈现时获得一个额外的侦听器。由于这是一个功能组件,您应该将这些行包装在一个效果挂钩中,以便您可以控制它们何时运行。
useEffect(() =>
window.ethereum.on('chainChanged', (_chainId) => checkChainID());
window.ethereum.on('accountsChanged', (_accounts) => loadBlockchainData());
checkChainID();
return () =>
// remove the 'chainChanged' and 'accountsChanged' event listeners
, [])
空数组告诉这个效果只在组件第一次渲染时运行一次。如果您需要它在某些状态发生变化时运行,或者您需要访问效果中运行的函数内的任何状态变量,则需要在依赖数组中列出这些变量。
您还需要从删除您的侦听器的钩子中返回一个函数,这样他们就不会在每次用户访问页面、离开和返回时继续增加。
你可以阅读更多关于useEffect
here的信息。
【讨论】:
哦,这就是我当时正在寻找的,useEffect!非常感谢,它解决了我的问题。我将立即阅读更多相关信息。以上是关于React 路由组件多次调用函数的主要内容,如果未能解决你的问题,请参考以下文章