【问题标题】:Cancel only current axios request in React application仅取消 React 应用程序中的当前 axios 请求
【发布时间】:2019-09-10 09:20:36
【问题描述】:

在我的应用程序中,我有一个按钮,每次点击都会在服务器上上传新文件(axios POST 方法)。在上传期间,我有另一个按钮可以取消该请求。

问题:如果我有多个活动上传并单击其中一个的取消按钮,则只会取消最后一个请求。即如果我想取消总共三个的第二次上传,第三个将是取消的那个。

问题:如何解决这个问题并通过单击取消按钮仅中止当前请求(单击取消按钮的请求)?

这是一个界面截图:

这是我的简化代码:

带有上传按钮的包装器:

import React from 'react';
import Types from 'prop-types';
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  MenuItem,
  TextField,
  Select,
  InputLabel,
} from '@material-ui/core';
import FormControl from '@material-ui/core/FormControl';
import Button from '@material-ui/core/Button';
import FileInput from 'components/Inputs/FileInput';
import ProgressBar from 'components/ProgressBar/ProgressBar';
import axios from 'axios';

class CreateDocumentComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      data: [],
      fieldValue: null,
      file: {},
      requestCounter: 0,
      requestArr: [],
      showTitle: false,
    }
  }

/* When button been clicked one more time - add new upload progress bar */
      componentDidUpdate(prevProps, prevState, snapshot) {
        if (prevState.requestCounter !== this.state.requestCounter) {
          this.setState({
            requestArr: this.state.requestArr.concat(
              <ProgressBar
                fileData={this.state.fileData}
                cutTitle={this.cutTitle}
              />
            )
          });
        }
      }

  render() {
    const { open, cancel, row, submit, onFieldChange } = this.props;
    const { data } = this.state;

    return (
      <Dialog open={open} onClose={cancel}>
        <DialogTitle>{'Прикрепить новый документ'}</DialogTitle>
        <DialogContent>
          <DialogActions>
            <Button color="secondary" onClick={() => {
              this.incrementCounter();
              this.changeTitleVisibility(false);
            }}>
              {'Upload'}
            </Button>
            <Button color="primary" disabled={!(row.file && row.number)} onClick={submit}>
              {'Save'}
            </Button>
            <Button color="secondary" onClick={cancel}>
              {'Back'}
            </Button>
          </DialogActions>

          {this.state.requestArr && this.state.requestArr.map((item, index) => item)}
        </DialogContent>
      </Dialog>
    );
  }
};

export default CreateDocumentComponent;

带有进度条和上传功能的模块:

import React from 'react';
import {IconButton} from "@material-ui/core";
import axios from "axios";
import CancelIcon from '@material-ui/icons/Cancel';
import { withStyles, styled } from '@material-ui/styles';

const MyIconButton = styled(IconButton)({
  paddingTop: '0',
  paddingBottom: '0'
});

// Initiating cancel token for each upload
    const CancelToken = axios.CancelToken;
    let cancel;

class ProgressBar extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      percentage: 0,
      status: '',
      res: '',
    }
  };

// when module is mounted - make a request
 componentDidMount() {
    const { fileData } = this.props;

    let dataa = new FormData();
    dataa.append('data', fileData);
    dataa.append('number', 3434);
    dataa.append('taskId', 157530);

    const config = {
      cancelToken: new CancelToken(c => {
        // this function will receive a cancel function as a parameter
        cancel = c;
      }),
      onUploadProgress: progressEvent => {
        let percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total );
        this.changePercentage(percentCompleted);
      }
    };

    this.changeStatus('');

    axios
      .post(`/bpm/attachments`, dataa, config)
      .then(res => {
        if (res) {
          this.changeResult(res.data);
          this.changeStatus('Loaded');
        } else {
          this.changeStatus('Canceled');
          this.changePercentage(100);
        }
      })
      .catch(error => {
        this.changeStatus('Error');
      });
  };

  cancelRequest = () => {
    cancel('Loading is canceled');
  };

  changePercentage = val => {
    this.setState({
      percentage: val,
    });
  };

  changeStatus = val => {
    this.setState({
      status: val
    });
  };

  changeResult = val => {
    this.setState({
      res: val
    });
  };

  render() {
    const { classes, fileData, cutTitle } = this.props;
    return (
      <React.Fragment>
        <div className={classes.progressBlock} style={{'display' : fileData ? 'block' : 'none'}}>
          <div className={classes.fileName}>{(fileData && (this.state.percentage > 0)) ? cutTitle(fileData.name) : ''}</div>
          <progress className={`
            ${classes.progressBar} ${this.state.status === 'Canceled'
              ? classes.progressBarCanceled
              : this.state.status === 'Error'
                ? classes.progressBarError
                : ''}
          `} value={this.state.percentage} max="100"></progress>
          <MyIconButton style={{
            'display': this.state.status.length ? 'none' : 'inline-block'
          }} onClick={() => this.cancelRequest()} title="Canceled">
            <CancelIcon />
          </MyIconButton>
          <div className={classes.uploadStatus} style={
            {'color': (this.state.status === 'Canceled' || this.state.status === 'Error') ? '#f50057' : 'rgba(0, 0, 0, 0.87)'}
          }>{this.state.status}</div>
        </div>
      </React.Fragment>
    );
  }
}

export default withStyles(styles)(ProgressBar);

【问题讨论】:

  • 我要做的第一件事就是在你自己的 javascript 模块中包装这些糟糕的东西,这就是我存放取消方法的地方。你不应该在你的反应组件中混合关注点。使您的代码 TL;DR

标签: javascript reactjs axios


【解决方案1】:

这是因为您在组件外部创建了 cancelToken 并为每个组件实例重写它。这是修复:

包装组件:

let CancelToken = axios.CancelToken;

<ProgressBar
   cancelToken={CancelToken}
/>

ProgressBar 组件:

class ProgressBar extends React.Component {
   constructor(props) {
      super(props);

      this.cancel;
   };

   const config = {
      cancelToken: new cancelToken(c => {
         this.cancel = c;
      }),
      onUploadProgress: progressEvent => {
         let percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total );
         this.changePercentage(percentCompleted);
      }
   };

   axios.post(/bpm/attachments, dataa, config)
   .then(res => {})
   .catch(error => {})

   cancelRequest = () => {
      this.cancel('Request is canceled');
   };

【讨论】:

  • ^ 顶级评论在这里!像魅力一样工作!
猜你喜欢
  • 2021-04-03
  • 1970-01-01
  • 2020-06-23
  • 2021-07-02
  • 2019-11-26
  • 2018-11-04
  • 2021-01-07
  • 2017-12-11
  • 1970-01-01
相关资源
最近更新 更多