反应 useEffect 依赖不从异步回调触发

React useEffect dependency not triggering from async callback

我试图将其分解为最简单的组件,以理解为什么 ButtonStatus 中的 useEffecteventDataId 中的状态更新时未更新的原因ButtonView React 组件的 14=] 函数。在这个例子中,我在我的本地 Ganache 实例上调用以太坊的智能合约,它工作正常并在每次调用时返回一个新的 eventDataId。

用例:用户点击按钮,handleButtonClick 触发请求(在本例中是以太坊智能合约调用),在 on() 函数中,我们设置状态eventDataId。我 希望 这将通过它的依赖项数组触发 ButtonStatus useEffect,特别是 [eventDataId]。我认为这反过来应该查找其他信息并呈现 MintStatus.

// I've removed all extraneous lines of code, for example the .catch() and .error() handlers on the contract.methods calls.

import React, { useEffect, useState} from 'react';
const Web3 = require('web3');

const ButtonStatus = ({contract, account}) => {

    const [eventDataId, setEventDataId] = useState();
    const [additionalData, setAdditionalData] = useState();

    function retrieveAdditionalData(contract, account) {
        contract.methods.additionalData()
        .call({ from: account })
        .then(function(res) {
            setAdditionalData(res);
        });
    }

    useEffect(() => {
        retrieveAdditionalData(contract, account);
    }, [eventDataId]);

    return (
        <div>Event Data Id is {eventDataId} with {additionalData}</div>
    );
}

class ButtonView extends React.Component {

    constructor(props, context) {
        super(props, context);
        this.state = {
            eventDataId: undefined
        };
        this.handleButtonClick = this.handleButtonClick.bind(this);
    }

    handleButtonClick() {
        const setState = this.setState.bind(this);   
        const contract = this.props.contract;
        const account = this.props.account;

        contract.methods.doSomething()
        .send({ from: account })
        .on('confirmation', function(confirmationNumber, receipt){
            let eventDataId = receipt.events['Data Event'].returnValues.eventDataId;
            setState({ eventDataId: eventDataId });
        });      
    }

    render() {
        return (
            <button onClick={this.handleButtonClick}>Click Me</button>
            <ButtonStatus contract={this.props.contract} account={this.props.account} />
        );
    }
}

export default ButtonView;

我确定我在这里遗漏了一些基本概念。 React{ useState } 的幕后“工作原理”是否甚至将 ButtonView 中的 eventDataId state 值关联到 ButtonStatus 中的 state 值.我怀疑这就是问题所在。

简而言之,我正在寻求帮助以了解 contract.methods.doSomething().on(...) 的响应如何触发 ButtonStatususeEffect

当父 ButtonView 中的 eventDataId 状态更新时,您似乎希望 useEffect 挂钩 ButtonStatus 到 运行。当父级中的状态更新时,它将触发重新渲染,从而重新渲染子 ButtonStatus 组件。您可以将 this.state.eventDataId 作为道具传递给 useEffect 的依赖项数组。

按钮视图

render() {
  return (
    <button onClick={this.handleButtonClick}>Click Me</button>
    <ButtonStatus
      contract={this.props.contract}
      account={this.props.account}
      eventDataId={this.state.eventDataId}
    />
  );
}

按钮状态

const ButtonStatus = ({ account, contract, eventDataId }) => {
  const [additionalData, setAdditionalData] = useState();

  function retrieveAdditionalData(contract, account) {
    contract.methods.additionalData()
      .call({ from: account })
      .then(function(res) {
        setAdditionalData(res);
      });
  }

  useEffect(() => {
    retrieveAdditionalData(contract, account);
  }, [eventDataId]);

  return (
    <div>Event Data Id is {eventDataId} with {additionalData}</div>
  );
}