import React from 'react'; import { connect } from 'react-redux'; import { Result } from 'mycrypto-nano-result'; import ERC20 from 'libs/erc20'; import { shepherdProvider } from 'libs/nodes'; import { AppState } from 'features/reducers'; import { walletSelectors } from 'features/wallet'; import Spinner from 'components/ui/Spinner'; import { Input } from 'components/ui'; interface OwnProps { address?: string; } interface StateProps { walletInst: ReturnType; } interface State { balance: Result; addressToLoad?: string; loading: boolean; } type Props = OwnProps & StateProps; class BalanceFieldClass extends React.Component { public static getDerivedStateFromProps( nextProps: OwnProps, prevState: State ): Partial | null { if (nextProps.address && nextProps.address !== prevState.addressToLoad) { return { loading: true, addressToLoad: nextProps.address }; } return null; } public state: State = { balance: Result.from({ res: '' }), loading: false }; private currentRequest: Promise | null; public componentDidUpdate() { if (this.state.addressToLoad && this.state.loading) { this.attemptToLoadBalance(this.state.addressToLoad); } } public componentWillUnmount() { if (this.currentRequest) { this.currentRequest = null; } } public render() { const { balance, loading } = this.state; return ( ); } private attemptToLoadBalance(address: string) { // process request this.currentRequest = this.loadBalance(address) // set state on successful request e.g it was not cancelled // and then also set our current request to null .then(({ balance }) => this.setState({ balance, loading: false }) ) .catch(e => { console.error(e); // if the component is unmounted, then dont call set state if (!this.currentRequest) { return; } // otherwise it was a failed fetch call this.setState({ loading: false }); }) .then(() => (this.currentRequest = null)); } private loadBalance(address: string) { if (!this.props.walletInst) { return Promise.reject('No wallet found'); } const owner = this.props.walletInst.getAddressString(); return shepherdProvider .sendCallRequest({ data: ERC20.balanceOf.encodeInput({ _owner: owner }), to: address }) .then(ERC20.balanceOf.decodeOutput) .then(({ balance }) => { const result = Result.from({ res: balance }); return { balance: result }; }); } } function mapStateToProps(state: AppState): StateProps { return { walletInst: walletSelectors.getWalletInst(state) }; } export const BalanceField = connect(mapStateToProps)(BalanceFieldClass);