不断重新渲染是否会使我的 react dapp 变慢?还是 web3 有问题?

问题描述

我目前正在尝试从头开始编写一个 dapp,使用 Dapp 大学的 EthSwap (https://github.com/dappuniversity/eth_swap) 作为模型(基本上是尝试在不查看他的代码的情况下重新创建这个 dapp)。基本上,dapp 只允许您购买 erc20 代币。它似乎确实有效,但它确实很慢。我认为这可能是 react 的问题,因为我目前是该框架的新手,可能已经陷入了一些性能问题。我尝试了以下方法以确保消除其他原因:

  1. 更改浏览器(Chrome --> Brave)并在两者上安装和使用元掩码
  2. 从 ganache gui 切换到 ganache-cli
  3. 我将与 web3 的连接视为一个单独的组件并将其导入,但最后只是将此代码放在 App.js 中

这是我的代码

// App.js

import './App.css';
import PageNavbar from './components/PageNavbar';
import TokenExchangeForm from './components/TokenExchangeForm';
import Web3 from 'web3';
import { useContext,useState,useEffect } from 'react';
import GenericToken from './abis/GenericToken.json';
import TokenExchange from './abis/TokenExchange.json';




function App() {

  const [account,setAccount] = useState('');
  const [ethBalance,setEthBalance] = useState('');
  const [tokenBalance,setTokenBalance] = useState('');
  const [genericToken,setGenericToken] = useState(null);
  const [tokenExchange,setTokenExchange] = useState(null);



  useEffect(() => {
     const init = async () => {
       await getWeb3();
       await getBlockchainData();
     }
     init();
  });


  const getBlockchainData = async () => {

    const web3 = window.web3

    let retrievedAccounts = await web3.eth.getAccounts();
    setAccount(retrievedAccounts[0]);

    let ethBalance = await web3.eth.getBalance(retrievedAccounts[0]);
    setEthBalance(web3.utils.fromWei(ethBalance.toString(),'Ether'));

    let networkId = await web3.eth.net.getId()
    let genericTokenData = GenericToken.networks[networkId];
    let tokenExchangeData = TokenExchange.networks[networkId];


    let genericToken = new web3.eth.Contract(GenericToken.abi,genericTokenData.address);
    setGenericToken(genericToken);

    let tokenExchange = new web3.eth.Contract(TokenExchange.abi,tokenExchangeData.address);
    setTokenExchange(tokenExchange);


    let tokenBalance = await genericToken.methods.balanceOf(retrievedAccounts[0]).call();
    setTokenBalance(web3.utils.fromWei(tokenBalance.toString(),'Ether'));
  }

  const getWeb3 = async () => {

    if (window.ethereum) {
      window.web3 = new Web3(window.ethereum);
      try {
        await window.ethereum.request({ method: 'eth_requestAccounts' });
      
      } catch (err) {
        console.log('Transaction rejected by user:',err)
      }
    }
    else if (window.web3) {
      window.web3 = new Web3(window.web3.currentProvider);
    }
    else {
      console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
    }


  }

  let buy = (etherAmount) => {
    //const gasEstimate = await tokenExchange.methods.buy().estimateGas({ from: account,value: window.web3.utils.toWei(etherAmount,'ether') });
    //const gasPriceEstimate = await window.web3.eth.getGasPrice();
    tokenExchange.methods.buy().send({ from: account,'Ether')});
  }

  return (
    <div className="App">
        <PageNavbar title='Token Exchange' account={account}/>
        <TokenExchangeForm ethBalance={ethBalance} tokenBalance={tokenBalance}  buy={buy}></TokenExchangeForm>
    </div>
  );
}



export default App;

// TokenExchangeForm.js

import Card from 'react-bootstrap/Card';
import Container from 'react-bootstrap/esm/Container';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import { useState } from 'react';
import ExchangeField from './ExchangeField';



const TokenExchangeForm = (props) => {
    const [etherValue,setEtherValue] = useState('');
    const [tokenValue,setTokenValue] = useState('');

    const changeHandlerEth = (event) => {
        setEtherValue(event.target.value);
    }

    const changeHandlerToken = (event) => {
        setTokenValue(window.web3.utils.fromWei(etherValue,'Ether'));
    }

    const submitHandlerBuy = (event) => {
        event.preventDefault();
        props.buy(etherValue);
    }

    return(
            <Container>
                <Card id="centered-form">
                    <Form onSubmit={submitHandlerBuy}>
                        <Container>
                            <br />
                            <ExchangeField label ='Input' balance={props.ethBalance} value={props.etherValue} onChange={changeHandlerEth} placeholder='0' appendtext ="ETH"/>
                            <br/>
                            <ExchangeField label='Output' balance={props.tokenBalance} value={props.tokenValue} onChange={changeHandlerToken} placeholder='0' appendtext="GT"/>
                            <br />
                            <Form.Row>
                                <Form.Label>Exchange Rate</Form.Label>
                                <Form.Label className='add-space'>1 ETH = 100 GT</Form.Label>
                            </Form.Row>
                            <br />
                            <Button type='submit' variant="primary" size="lg" className ="w-100" block>
                                SWAP
                            </Button>
                        </Container>
                    </Form>
                </Card>
            </Container>
    );
}

export default TokenExchangeForm;

解决方法

我解决了我的问题。事实证明 useEffect 在每次渲染后都会继续运行,因此它不断地重新加载 web3,从而减慢了应用程序的速度。您可以通过在 useEffect 中添加一个空数组来防止这种情况:

 useEffect(() => {
     const init = async () => {
       await getWeb3();
       await getBlockchainData();
     }
     init();
  },[]);

这允许 useEffect 仅在安装组件时运行。查看此帖子以了解更多信息:https://stackoverflow.com/a/53464623/4421062

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...