特定的 React 模型有时不会加载,需要重新渲染

Specific React model doesn't load sometimes and needs rerendering

我是 Solidity 和 React 的初学者,现在我正在尝试使用 React 创建一个前端应用程序来与我的智能合约进行交互。我在我的应用程序的第一页制作了一个连接按钮,在使用 MetaMask 登录后将用户带到下一页。

在第二页,我加载了大部分关于合约的信息,如价格、最后铸造的 NFT 等。除了设置我最后铸造的 NFT 模型外,一切看起来都按顺序工作。

这是我的 index.js 的样子,我不使用 app.js,我使用 index.js 代替它。我遵循了一些关于浏览页面的教程并遵循了它,问题不在这个页面上,我只是展示它以获取更多信息:

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")
);

现在,我的铸币页面出现了我所说的问题。我的模型文件夹中有一个名为 jsonModel.js 的文件,如下所示:

export default {
    dna: '?',
    name: '?',
    edition: 0,
    attributes: []
}

我将值设置为“?”这样我就可以看到它们是否未加载。下面是我的 MintPage.js 代码,我基本上完成了此页面上的所有操作。事情是这样的:大多数时候,id 和 name 以“?”的形式出现。这表明它们没有加载,我在属性数组中加载了更多数据,在名为“setLatestMint”的函数中,但它似乎大部分时间都不起作用。当我重新加载页面时,它起作用了。有时不会。

我注意到当我点击一个使用 useState 参数的按钮时,模型加载,就像我重新加载页面时一样。所以看起来问题出在渲染上。当我执行某些操作以触发重新渲染时,数据似乎已加载。我试图手动重新渲染组件,我知道这不是推荐的方法,但即使这样也行不通,因为我不能使用“this”。所以我被困在这里,一无所知,做了几个小时的研究,但无法解决问题。任何帮助将不胜感激!

import React, { useState, useEffect } from 'react';
import Web3 from 'web3'
import impContract from "../src/impContract.js";
import jsonModel from "./model/jsonModel";

export const MintPage = (props) => {

  const web3 = window.web3;
  const [currentAccount, setCurrentAccount] = useState("0x0");
  const [currentBalance, setCurrentBalance] = useState("0");
  const [mintAmount, setMintAmount] = useState(1);
  const [mintCost, setMintCost] = useState(0);
  const [latestMintPic, setLatestMintPic] = useState("");
  const [feedback, setFeedback] = useState("Maybe it's your lucky day!");
  const [addAmount, setAddAmount] = useState(true);
  const [subtractAmount, setSubtractAmount] = useState(false);
  const [claimingNft, setClaimingNft] = useState(false);
  let [model] = useState(jsonModel);
  let lastMintJson;

  useEffect(() => {

    window.ethereum.on('chainChanged', (_chainId) => checkChainID());
    window.ethereum.on('accountsChanged', (_accounts) => loadBlockchainData());
    checkChainID();
    setLatestMint();

    return () => { }
  }, [])

  async function checkChainID() {
    const networkId = await web3.eth.net.getId();
    if (networkId !== 4) {
      props.history.push("/")
    } else {
      loadBlockchainData();
    }
  }

  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");
    loadContract();
  }

  async function loadContract() {
    const ContractObj = impContract;
    const costResult = await ContractObj.methods.cost().call();
    var costEth = web3.utils.fromWei(costResult, 'ether');
    setMintCost(parseFloat(costEth).toFixed(2));
  }

  async function setLatestMint() {
    const ContractObj = impContract;
    const latestMintResult = await ContractObj.methods.totalSupply().call();
    setLatestMintPic("https://nftornek.000webhostapp.com/cryptonauts/image/" + latestMintResult + ".png");
    lastMintJson = "https://cors-anywhere.herokuapp.com/https://nftornek.000webhostapp.com/cryptonauts/json/" + latestMintResult + ".json";


    var x = new XMLHttpRequest();
    x.open('GET', lastMintJson);
    x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    x.onload = function () {
      model = setNFTModel(JSON.parse(x.responseText));
      console.log(model);

    };
    x.send();

  }

  function setNFTModel(jsonObj) {
    model.dna = jsonObj.dna;
    model.name = jsonObj.name;
    model.edition = jsonObj.edition;

    if (model.attributes.length > 0) {
      model.attributes = []
    }
    for (var x = 0; x < jsonObj.attributes.length; x++) {
      model.attributes.push(jsonObj.attributes[x]);
    }

    return model;

  }


  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={{ display: 'flex', justifyContent: 'center', }}><h1>Latest Mint:</h1></div>
      <div style={{ display: 'flex', justifyContent: 'center', marginBottom: '30px', height: '350px' }}>
        <div style={{ width: '350px', border: '2px solid #38495a', borderRadius: '5px' }}><img src={latestMintPic}></img>
        </div>
        <div style={{ width: '300px', padding: '10px', border: '2px solid #38495a', borderRadius: '4px', backgroundColor: 'rgba(56, 73, 90, 0.25)'}}><t1>ID: {model.edition}<br></br> Name: {model.name}
          <table className="tableClass t1">
            <tbody>
              {model.attributes.map(item => (
                <tr key={item.trait_type}>
                  <td key={1}>{item.trait_type}:</td>
                  <td key={2}>{item.value}</td>
                </tr>
              ))}
            </tbody>
          </table></t1></div>
      </div>
      <div style={{ display: 'flex', justifyContent: 'center', color: '#38495a' }}>{feedback}</div>
      <div style={{ display: 'flex', justifyContent: 'center' }}><p className="accountText">Mint <b>{mintAmount}</b> Cryptonaut for <b>{mintCost * mintAmount}</b> 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" disabled={claimingNft ? 1 : 0} onClick={() => {
          claimNFTs(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: <b>{currentBalance}</b></p></div>
    </div>

  )
}

我已经通过更改这些行解决了这个问题:

var x = new XMLHttpRequest();
    x.open('GET', lastMintJson);
    x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    x.onload = function () {
      setModel(setNFTModel(JSON.parse(x.responseText)));
      console.log(model);

    };
    x.send();

进入这些:

let res = await axios.get(lastMintJson);
    setModel(setNFTModel(res.data))

现在,每次加载数据。我认为这是因为我无法异步发出旧请求。但是现在,有了 axios,我可以使用 await 关键字并阻止它在加载之前呈现。我的想法可能是错误的,但它现在有效。