javascript - Reactjs 中两个进度条组件的单一状态

标签 javascript reactjs ecmascript-6 state react-bootstrap

我已经创建了一个用于显示进度的通用组件。它需要一个 Prop “类型”来呈现进度的类型。类型是“条形”进度和“循环”进度。进度条显示,当我单击 Accordion 时,会显示循环进度,如下所示:

both progress bars

我想要的是,如果我在任何进度(条形或圆形)上单击暂停,两个进度都应该停止。这是这个通用进度组件的代码:

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/

相关文章:

ruby-on-rails - 客户端服务架构 : keep client in sync with in-memory data sctructure

javascript - onPress 在 iOS 设备的菜单中不起作用

javascript - ES6实现这个功能?

Javascript Date、setFullYear 更改时区

javascript - 为什么在异步函数中捕获后仍然抛出异常?

javascript - 如何更改 chromes 日期解析/排序以匹配 ff/ie 日期解析?

javascript - JS Map from Object.entries 内存使用情况

javascript - Jquery数据表 Entity Framework 复选框更新数据库

reactjs - 使用 Next.js 和 Vercel 隐藏 api key 的最简单方法?

javascript - 如何将 $q 提供程序插入到未包装到 Angular 模块中的类中?