【发布时间】: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