无法对间隔函数中卸载的组件问题执行 React 状态更新



我对带有间隔函数的组件将卸载有一些问题。所以我搜索如何在堆栈溢出和谷歌中解决这个问题,但我找不到正确的解决方案。

在我的本地机器中,控制台中没有错误,它只是向我显示Compiled successfully实际上,所有功能都运行良好。但是当我提交到 github 并在 Travis CI 中进行测试时,它向我显示了一个错误。所以我感到不舒服,因为我担心长时间运行这个网络应用程序时会出现内存泄漏。

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

我的区间函数在 componetDidMount(( 中,我添加了clearInterval(this.interval)代码来清除我在 componetWillUnmount 中的区间函数。

发现我必须在组件WillUnmount中编写代码来解决此问题,但是,似乎它不起作用。

还可以使用此 URL 签入代码沙盒

[邮政容器.js]

import React, { Component } from 'react';
import DataTable from 'react-data-table-component';
import axios from 'axios';
import { darkTheme, columns } from './tableSetting';
/* Price Comma Function */
function addComma(num) {
  let regexp = /B(?=(d{3})+(?!d))/g;
  return num.toString().replace(regexp, ',');
}
/* Title Component */
let titleComponent = (
  <div className="logoContainer">
    <a
      href="https://www.bithumb.com/"
      target="_blank"
      rel="noopener noreferrer">
      <img
        src="https://github.com/sangumee/Crypto-Table/blob/master/public/images/bithumb.png?raw=true"
        alt="bithumb LOGO"
        className="logo"
      />
    </a>
  </div>
);
/* Main Component */
class PostContainer extends Component {
  state = {
    title: <div className="Load">Load data from API Server...</div>,
    status: <div className="initLoading">LOADING WAIT!!</div>,
    data: [],
  };
  /* Error Catch */
  componentDidCatch(error, info) {
    console.log(error, info);
  }
  /* ComponentDidMount Cycle */
  async componentDidMount() {
    /* Exchange Rate USD to KRW */
    const exchangeResponse = await axios.get(
      `https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.KRWUSD`
    );
    const exchangeData = exchangeResponse.data[0].basePrice;
    this.getCoinData(exchangeData); // Initial get coin Data
    this.interval = setInterval(() => {
      this.getCoinData(exchangeData);
    }, 5000); // Interval 5 Seconds
  }
  componentWillUnmount() {
    clearInterval(this.interval);
    console.log('componentWillUnmount');
  }
  async getCoinData(exchangeData) {
    let chartData = []; //
    let status;
    const response = await axios.get(
      `https://api.bithumb.com/public/ticker/all`
    );
    const usdCoinData = await axios.get(
      `https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC,ETH,DASH,LTC,ETC,XRP,BCH,XMR,ZEC,QTUM,BTG,EOS,ICX,VET,TRX,ELF,MITH,MCO,OMG,KNC,GNT,ZIL,ETHOS,PAY,WAX,POWR,LRC,GTO,STEEM,STRAT,ZRX,REP,AE,XEM,SNT,ADA,PPT,CTXC,CMT,THETA,WTC,ITC,TRUE,ABT,RNT,PLY,WAVES,LINK,ENJ,PST,SALT,RDN,LOOM,PIVX,INS,BCD,BZNT,XLM,OCN,BSV,TMTG,BAT,WET,XVG,IOST,POLY,HC,ROM,AMO,ETZ,ARN,APIS,MTL,DACC,DAC,BHP,BTT,HDAC,NPXS,AUTO,GXC,ORBS,VALOR,CON,ANKR,MIX&tsyms=USD`
    );
    /* If API Status Success */
    if (response.data.status === '0000') {
      delete response.data.data['date']; // Remove 'date' data from object
      /* Create table data */
      for (let [key, value] of Object.entries(response.data.data)) {
        let premiumPrice, premiumPriceGap;
        if (typeof usdCoinData.data.DISPLAY[key] === 'undefined') {
          // If Coin data not exists set '-'
          premiumPrice = premiumPriceGap = '-';
        } else {
          /* Calculate USD * KRW data */
          let usdPrice =
            usdCoinData.data.DISPLAY[key].USD.PRICE.replace('$ ', '').replace(
              ',',
              ''
            ) * exchangeData;
          premiumPrice = (
            ((value.sell_price - usdPrice) / usdPrice) *
            100
          ).toFixed(2);
          premiumPriceGap = (value.sell_price - usdPrice).toFixed(2);
        }
        /* Create Final Data */
        chartData.push({
          key: key,
          Price: `${addComma(value.sell_price)}원`,
          FluctateRate: `${value['24H_fluctate_rate']}`,
          FluctateRate24: `${addComma(value['24H_fluctate'])}`,
          premium: addComma(premiumPrice),
          premiumGap: addComma(premiumPriceGap),
        });
      }
      /* If Server Status Success */
      this.setState({
        statue: status,
        result: 'success',
        data: chartData,
        title: (
          <div>
            {titleComponent}
            <div id="statusSuccess">{status}</div>
            <p className="apiSuccess"> API Works Fine</p>
          </div>
        ),
      });
    } else {
      /* If Server Status Fails */
      this.setState({
        statue: status,
        result: 'fail',
        title: (
          <div>
            {titleComponent}
            <div id="statusFail">{status}</div>
            <p className="apiFail"> API is not wokring. Something is Wrong</p>
          </div>
        ),
      });
    }
  }
  render() {
    const { data, title } = this.state;
    // console.log(data);
    return (
      <DataTable
        title={title}
        className="Post"
        columns={columns}
        data={data}
        customTheme={darkTheme}
        responsive={true}
        noDataComponent={this.state.status}
        fixedHeader
      />
    );
  }
}
export default PostContainer;

试试这个方式:


class PostContainer extends Component {
    _isMounted = false
    ...
    async componentDidMount() {
      this._isMounted = true
      /* Exchange Rate USD to KRW */
      const exchangeResponse = await axios.get(
        `https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.KRWUSD`
      );
      const exchangeData = exchangeResponse.data[0].basePrice;
      this.getCoinData(exchangeData); // Initial get coin Data
      this.interval = setInterval(() => {
        if (this._isMounted) this.getCoinData(exchangeData);
        else clearInterval(this.interval)
      }, 5000);
    }
    componentWillUnmount() {
      this._isMounted = false
    }
}

因为getCoinData正在await请求,所以即使它在取消模拟之前启动,它也可能在卸载后继续在this.setState行上(争用条件(。可以检查 react 组件是否已卸载,例如:

  componentWillUnmount() {
    clearInterval(this.interval);
    this.cancelSetState = true;
    console.log('componentWillUnmount');
  }
  async getCoinData(exchangeData) {
    ...
    if (this.cancelSetState) {
      return
    }
    /* If API Status Success */
    if (response.data.status === '0000') {
      ...

相关内容

  • 没有找到相关文章

最新更新