我已经创建了一个用于显示进度的通用组件。它需要一个 Prop “类型”来呈现进度的类型。类型是“条形”进度和“循环”进度。进度条显示,当我单击 Accordion 时,会显示循环进度,如下所示:
我想要的是,如果我在任何进度(条形或圆形)上单击暂停,两个进度都应该停止。这是这个通用进度组件的代码:
import React, {Component} from 'react';
import CircularProgressBar from 'react-circular-progressbar';
import config from '../../config';
import './Progress.css';
import './ProgressCircular.css';
class GenericProgress extends Component {
constructor(props) {
super(props);
this.state = {
progressPercent: props.progress,
width: "100%",
startTime: props.startTime,
progressStatus: props.status,
extractId: props.extractId,
};
this.tick=this.tick.bind(this);
}
tick() {
const reqObj={
"op": "progress",
"extractID" : this.props.extractId,
"last_ts" : this.state.last_ts,
"progress": this.state.progressPercent,
};
fetch(`${config.apiHost}/extracttool/extract`,
{
method: 'POST',
body: JSON.stringify(reqObj),
headers: {
'Content-Type': 'application/json'
}
}
).then((response) => {
return response.json();
}).then((data) => {
if(this.state.progressStatus !== 'Paused' ) {
const progressCounter = data.payload.progress;
const last_ts = data.payload.last_ts;
if (progressCounter >= 100) {
this.props.changeExecutionStatus('Complete');
this.setState({...this.state, progressPercent: 100, progressStatus: 'Complete'});
clearInterval(this.timerID);
} else {
this.setState({
...this.state,
progressPercent: progressCounter,
last_ts: last_ts
});
}
}
});
}
callApi = (reqObj, status) => {
fetch(`${config.apiHost}/extracttool/extract`,
{
method: 'POST',
body: JSON.stringify(reqObj),
headers: {
'Content-Type': 'application/json'
}
}
).then((response) => {
return response.json();
}).then((data) => {
this.setState({
progressStatus: status
});
});
}
componentDidMount() {
if (this.state.progressStatus === 'Progress' ) {
this.startTimer();
}
}
onPause = () => {
this.props.changeExecutionStatus('Paused');
clearInterval(this.timerID);
const reqObj={
op: "flow_control",
extractID: this.props.extractID,
value: "pause"
};
this.callApi(reqObj, 'Paused');
}
startTimer = () => {
this.timerID = setInterval(
() => this.tick(),
2500
);
}
onResume = () => {
this.props.changeExecutionStatus('Progress');
const reqObj={
op: "flow_control",
extractID: this.props.extractId,
value: "resume"
};
this.callApi(reqObj, 'Progress');
this.startTimer();
}
onCancel = () => {
this.props.changeExecutionStatus('Cancelled');
clearInterval(this.timerID);
const reqObj={
op: "flow_control",
extractID: this.props.extractId,
value: "cancel"
};
this.callApi(reqObj, 'Cancelled');
}
componentWillUnmount() {
clearInterval(this.timerID);
}
render() {
const { progressStatus, progressPercent, startTime } = this.state;
let progressClass = progressStatus === 'Complete' ? 'progress-bar progress-bar-success' : 'progress-bar';
if ( progressStatus === 'Paused' ) {
progressClass = 'progress-bar-warning progress-bar';
} else if( progressStatus === 'Cancelled' ) {
progressClass = 'progress-bar-danger progress-bar';
}
return (
<div className="progress-bar-container">
{
this.props.type === 'bar' &&
<div>
<div className="progress">
<span className="progressStartTime">Start Time: {startTime}</span>
<div
className={progressClass}
role="progressbar"
aria-valuenow={ progressPercent }
aria-valuemin="0"
aria-valuemax="100"
style={{width: progressPercent + "%"}}
>
</div>
</div>
<span className="extractProgress">{progressPercent < 100 ? progressStatus + ': '+this.state.progressPercent + '%' : 'Complete'}</span>
{
progressStatus === 'Paused' &&
<span className="playIcon" onClick={this.onResume}> </span>
}
{
progressStatus === 'Progress' &&
<span className="pauseIcon" onClick={this.onPause}> </span>
}
{
progressStatus !== 'Complete' && progressStatus !== 'Cancelled' &&
<span className="cancelIcon" onClick={this.onCancel}> </span>
}
</div>
}
{
this.props.type === 'circular' &&
<div>
<div className="CircularProgress">
{
progressStatus === 'Paused' &&
<span className="playIcon" onClick={this.onResume}> </span>
}
{
progressStatus === 'Progress' &&
<span className="pauseIcon" onClick={this.onPause}> </span>
}
<CircularProgressBar percentage={progressPercent} />
{
progressStatus !== 'Complete' && progressStatus !== 'Cancelled' &&
<span className="cancelIcon" onClick={this.onCancel}> </span>
}
</div>
</div>
}
</div>
);
}
}
export default GenericProgress;
这是我调用这些进度条和循环的组件:
import React from 'react';
import { Panel, Row } from 'react-bootstrap';
import {Link} from 'react-router-dom';
import GenericProgress from './GenericProgress';
import LogFile from './LogFile';
import moment from 'moment'
import './Extract.css';
class Extract extends React.Component {
constructor(props) {
super(props);
this.state = {
open: props.isOpen ? true : false,
executionStatus: this.props.data.execution_status
}
this.changeExecutionStatus = this.changeExecutionStatus.bind(this);
}
componentWillReceiveProps(newProps) {
if(this.props !== newProps){
if(this.state.executionStatus !== this.props.execution_status) {
console.log(this.state.executionStatus);
this.changeExecutionStatus(this.state.executionStatus);
}
}
}
changeExecutionStatus(status) {
this.setState({
executionStatus: status
})
}
render() {
const {name, progress, start_time, end_time, execution_status, id, engagement} = this.props.data;
const start_date_time = moment(start_time).format('MMMM Do YYYY, h:mm:ss a');
const end_date_time = moment(end_time).format('MMMM Do YYYY, h:mm:ss a');
const startTime = start_date_time.split(',')[1];
const startDate = start_date_time.split(',')[0];
const endTime = end_date_time.split(',')[1];
const endDate = end_date_time.split(',')[0];
return (
<div className="extract">
<div>
<span className={ this.state.open ? "arrowUpIcon" : "arrowDownicon" } onClick={() => {this.setState({open: !this.state.open})}}></span>
<h4>
{
this.props.clientDetails ?
<Link to={{
pathname: '/client/'+this.props.clientId,
state: {
extractId: id,
engagementId: engagement,
source: 'extractDirect'
}
}} >{name}</Link>
:
name
}
</h4>
<div className="progressBar">
<GenericProgress
type="bar"
progress={progress}
startTime={start_time}
status={this.state.executionStatus}
extractId={id}
changeExecutionStatus={this.changeExecutionStatus} />
</div>
<Panel collapsible expanded={this.state.open}>
<div>
<Row>
<div className="col-lg-3">
<div>
<GenericProgress
type="circular"
progress={progress}
startTime={start_time}
status={this.state.executionStatus}
extractId={id}
changeExecutionStatus={this.changeExecutionStatus} />
</div>
<br/>
<div>
<b>Start Time:</b> {startTime}
<br/>
<b>Start Date:</b> {startDate}
<br/><br/><br/>
<b>End Time:</b> {endTime}
<br/>
<b>End Date:</b> {endDate}
</div>
</div>
<div className="col-lg-9">
<LogFile
startDate={startDate}
startTime={startTime}
status={execution_status}
/>
</div>
</Row>
</div>
</Panel>
</div>
</div>
);
}
}
export default Extract;
最佳答案
现在您有两个真实来源
。父组件中的进度状态
和每个Progress
组件中的进度状态
。
您应该使 Progress
组件非常愚蠢。它应该只渲染给定的 Prop 。
将您的 fetch
逻辑移到父组件中,并从中更改进度状态。
关于javascript - Reactjs 中两个进度条组件的单一状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45177112/