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

Posted

技术标签:

【中文标题】不断的重新渲染是不是会使我的反应 dapp 变慢?还是web3有问题?【英文标题】:Is constant re-rendering making my react dapp slow? Or is it a problem with web3?不断的重新渲染是否会使我的反应 dapp 变慢?还是web3有问题? 【发布时间】:2021-08-28 15:24:48 【问题描述】:

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

    更改浏览器(Chrome --> Brave)并在两者上安装和使用元掩码 从 ganache gui 切换到 ganache-cli 我把到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, value: window.web3.utils.toWei(etherAmount, '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;

【问题讨论】:

react 非常聪明,如果它返回相同的状态,它不应该在设置时重新渲染。 我在想这也可能是我所做的表单处理。我确实注意到当我按下提交按钮时它变慢了。 【参考方案1】:

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

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

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

【讨论】:

以上是关于不断的重新渲染是不是会使我的反应 dapp 变慢?还是web3有问题?的主要内容,如果未能解决你的问题,请参考以下文章

将 Oracle 的行大小设置得更高会使我的应用程序变慢?

为啥在使用 FBO 进行多重采样时,OpenGL 会使我的场景变亮?

React,是不是在父级上渲染会使子级重新渲染?

反应本机重新渲染导致视图滚动到顶部-我的键在渲染之间是不是发生变化?

如何从无限重新渲染中停止反应组件

为啥要在标记点击事件上重新渲染地图?