如何在反应中使用redux取消以前的axios

Posted

技术标签:

【中文标题】如何在反应中使用redux取消以前的axios【英文标题】:how to cancel previous axios with redux in react 【发布时间】:2018-08-20 09:24:54 【问题描述】:

我的操作文件中有以下操作。

import axios from 'axios';
import $ from 'jquery';
var CancelToken = axios.CancelToken;
var source = CancelToken.source();

export const FETCH_WORKERJOBS = 'fetch_workerjobs';

export function fetchWorkerJobs(page, size, where, sort) 
    const request = axios.get(`/api/user/report/comms/matrix/upload/format/json?quiet=1&page=`+page+`&size=`+size+`&where=`+JSON.stringify(where)+`&sort=`+sort,cancelToken: source.token);   
    return 
        type: FETCH_WORKERJOBS,
        payload: request
    ;


export const FETCH_WORKERJOBS_COUNT = 'fetch_workerjobs_count';

export function fetchWorkerJobsCount(where) 
    const request = axios.get(`/api/user/report/comms/matrix/upload/count/format/json?quiet=1&where=`+JSON.stringify(where), cancelToken: source.token);  
    return 
        type: FETCH_WORKERJOBS_COUNT,
        payload: request
    ;

当我将函数导入我的组件时,如何访问cancel 令牌以取消

import _ from 'lodash';
import React,  Component  from 'react';
import  connect  from 'react-redux';
import  fetchWorkerJobs, fetchWorkerJobsCount  from '../../actions';
import  Link  from 'react-router-dom';
import  bindActionCreators  from 'redux';
import  Button, ButtonToolbar, Modal  from 'react-bootstrap';
import FontAwesome from 'react-fontawesome';
import 
    BootstrapTable,
    TableHeaderColumn,
    InsertModalHeader,
    InsertModalFooter
 from 'react-bootstrap-table';
import 'react-bootstrap-table/dist/react-bootstrap-table-all.min.css';
import $ from 'jquery';

const jobType = 
        

class WorkerJobs extends Component 
    constructor(props) 
        super(props);
        this.workerJobs = [];
        this.state = 
            data: [],
            show: false,
            showError: false,
            errorMsg: '',
            errorTitle: '',
            record: ,
            showEdit: false,
            confirm: 
                body: '',
                show: false,
                id: ''
            ,
            totalDataSize: 0,
            currentPage: 1

        ;
        this.where = ;
        this.sort = 'worker_job_id desc';
        this.meta =  title: 'Report - Worker Jobs', description: 'List of jobs processed' ;
        this.error = show: false,msg:'';
        this.passMetaBack = this.passMetaBack.bind(this);
        this.options = 
            defaultSortName: 'worker_job_id', // default sort column name
            defaultSortOrder: 'desc', // default sort order
            page: 1,
            paginationShowsTotal: true,
            sizePerPage: 10,
            sizePerPageList: [10,25,50],
            onPageChange: this.onPageChange.bind(this),
            onSizePerPageList: this.onSizePerPageList.bind(this),
            onFilterChange: this.onFilterChange.bind(this),
            onSortChange: this.onSortChange.bind(this)
        ;

        this.fetchWorkerJobs = this.fetchWorkerJobs.bind(this);

        this.runOnce = false;
    

    onPageChange(page, sizePerPage) 
        const currentIndex = (page - 1) * sizePerPage;
        this.options.page = page;
        console.log(this.props);
        this.props.fetchWorkerJobsCount.cancel(); //not working
        this.props.fetchWorkerJobs.cancel(); //not working
        console.log(this.props);
        this.fetchWorkerJobs(page, sizePerPage, this.where, this.sort);
      

    onSizePerPageList(sizePerPage) 
        const currentIndex = (this.state.currentPage - 1) * sizePerPage;
        this.options.sizePerPage = sizePerPage;
        this.fetchWorkerJobs(this.options.page, sizePerPage, this.where, this.sort);
      

    onFilterChange(filterObj) 

        let where = ;
        for (const key in filterObj) 
            where[key] = filterObj[key].value;
        
        this.where = where;
        this.fetchWorkerJobs(this.options.page,this.options.sizePerPage,this.where, this.sort);
      

    onSortChange(sortName, sortOrder) 
        this.sort = sortName + " " + sortOrder;
        this.fetchWorkerJobs(this.options.page,this.options.sizePerPage,this.where, this.sort);
      



    fetchWorkerJobs(page, size, where, sort)
        let self = this;   
        this.props.fetchWorkerJobsCount(where).then(function(response)
            let data = response.payload.data;
            if(data.header.error)
                //@todo show error on input form
                //self.handleShowError(data.header.message);                
            else
                return data.body.recordset.record;

            
        )
        .then((count)=>
            this.props.fetchWorkerJobs(page, size, where, sort).then(function(response)
                let data = response.payload.data;
                if(data.header.error)
                    //@todo show error on input form
                    //self.handleShowError(data.header.message);                
                else
                    self.options.page = page;
                    self.options.sizePerPage = size;
                    self.workerJobs = data.body.recordset.record;
                    self.setState(
                        data : data.body.recordset.record,
                        totalDataSize : count
                    );
                
            );
        );

    

    moveElement() 
      //store a this ref, and
      var _this = this;
      //wait for a paint to do scrolly stuff
      window.requestAnimationFrame(function() 
          if($(".react-bs-table-tool-bar").length > 0)
              if($(".react-bs-table-tool-bar .react-bs-table-sizePerPage-dropdown").length <= 0)

                  $(".react-bs-table-sizePerPage-dropdown").prependTo(".react-bs-table-tool-bar");
              
          
      );
    

    renderTable(services) 

        return (
            <BootstrapTable
                keyField="worker_job_id"
                data=services
                remote
                //multiColumnSearch
                fetchInfo=  dataTotalSize: this.state.totalDataSize  
                options=this.options
                pagination
                striped
                hover
                //insertRow
                //search
                tableHeaderClass="table-vf thead"
                exportCSV
                tableContainerClass="report_workerjobs"
            >
                <TableHeaderColumn dataField="worker_job_id" dataSort=true width=`60px`>
                    #
                </TableHeaderColumn>
                <TableHeaderColumn dataField="job" filter=  type: 'SelectFilter', options: jobType  >Job</TableHeaderColumn>
                <TableHeaderColumn dataField="filename">Filename</TableHeaderColumn>
                <TableHeaderColumn
                    dataField="flag"
                    filter= type: 'TextFilter', defaultValue: 'C' 
                    width=`60px`
                >
                    Flag
                </TableHeaderColumn>
                <TableHeaderColumn dataField="total_time_taken" width=`125px`>Total Time Taken</TableHeaderColumn>
                <TableHeaderColumn dataField="output" width=`100px`>Analysis</TableHeaderColumn>
                <TableHeaderColumn dataField="ts_created">Created</TableHeaderColumn>
                <TableHeaderColumn dataField="ts_updated">Finished</TableHeaderColumn>     
                <TableHeaderColumn dataField="comms_matrix_id" width=`60px`>#CM</TableHeaderColumn>
                <TableHeaderColumn dataField="visible_lines" width=`100px`>Visible Lines</TableHeaderColumn>
                <TableHeaderColumn 
                    dataField="security_flows" 
                    width=`100px` 
                    thStyle=
                        whiteSpace: 'pre-wrap',
                        whiteSpace: '-moz-pre-wrap',
                        whiteSpace: '-pre-wrap',
                        whiteSpace: '-o-pre-wrap',
                        wordWrap: 'break-word'
                         
                >
                    Security Flows
                </TableHeaderColumn>

            </BootstrapTable>
        );
    

    render() 
        if(!this.runOnce && this.props.isReady)             
            this.runOnce = true;
            this.fetchWorkerJobs(this.options.page, this.options.sizePerPage, this.where, this.sort);
        

        let table = <div>Loading...<i className="fa fa-spinner fa-spin"></i></div>;
        if ( Object.keys(this.props.reportsWorkerJobs).length > 0) 
            table = this.renderTable(this.state.data);
            this.moveElement();
        

        return (
            <div className="container-fluid">
                <div className="row-fluid top-buffer">table</div>
            </div>
        );
    


function mapStateToProps(state) 

    return 
        reportsWorkerJobs: state.reportsWorkerJobs,
        reportsWorkerJobsCount: state.reportsWorkerJobsCount
    ;


function mapDispatchToProps(dispatch) 
    return bindActionCreators(
         fetchWorkerJobs, fetchWorkerJobsCount ,
        dispatch
    );


export default connect(mapStateToProps, mapDispatchToProps)(WorkerJobs);

我想取消以前的分页请求等。我需要取消

this.props.fetchWorkerJobsCount.cancel(); //not working
        this.props.fetchWorkerJobs.cancel(); //not working

我尝试从动作文件中导出变量并导入到组件中,但不起作用

actions.js

export const FETCH_WORKERJOBS_COUNT_CANCEL = wjc_cancel;

组件

...
import  fetchWorkerJobs, fetchWorkerJobsCount, FETCH_WORKERJOBS_COUNT_CANCEL, FETCH_WORKERJOBS_CANCEL  from '../../actions';
...
onPageChange(page, sizePerPage) 
        const currentIndex = (page - 1) * sizePerPage;
        this.options.page = page;
        FETCH_WORKERJOBS_COUNT_CANCEL();
        FETCH_WORKERJOBS_CANCEL();
        this.fetchWorkerJobs(page, sizePerPage, this.where, this.sort);
      

我得到的错误是Uncaught TypeError: (0 , _actions.FETCH_WORKERJOBS_COUNT_CANCEL) is not a function

更新

我试图将它作为变量传递给操作函数,但一些请求似乎通过了。我正在做的是非常快地按下分页上的下一个按钮。大多数会被取消,但有些不会。

export function fetchWorkerJobs(page, size, where, sort, cancelled) 
    if(cancelled)
        wj_cancel();

    
    const request = axios.get(`/api/user/report/comms/matrix/upload/format/json?quiet=1&page=`+page+`&size=`+size+`&where=`+JSON.stringify(where)+`&sort=`+sort,
        cancelToken: new CancelToken(function executor(c) 
            // An executor function receives a cancel function as a parameter
            wj_cancel = c;
        )
    ); 
    return 
        type: FETCH_WORKERJOBS,
        payload: request
    ;

【问题讨论】:

【参考方案1】:

您需要访问source 变量才能取消它。

或者,您可以在创建新请求时取消先前的请求(这似乎是您的用例)。

类似于以下内容(使用执行器函数语法:https://github.com/axios/axios#cancellation,因此您会为每个请求获得一个新令牌

import axios from 'axios';
import $ from 'jquery';
var CancelToken = axios.CancelToken;
let wj_cancel, wjc_cancel;

export const FETCH_WORKERJOBS = 'fetch_workerjobs';

export function fetchWorkerJobs(page, size, where, sort) 
  wj_cancel && wj_cancel();
  const request = axios.get(`/api/user/report/comms/matrix/upload/format/json?quiet=1&page=` + page + `&size=` + size + `&where=` + JSON.stringify(where) + `&sort=` + sort, 
    cancelToken: new CancelToken(function executor(c) 
        // An executor function receives a cancel function as a parameter
        wj_cancel = c;
      
  );
  return 
    type: FETCH_WORKERJOBS,
    payload: request
  ;


export const FETCH_WORKERJOBS_COUNT = 'fetch_workerjobs_count';

export function fetchWorkerJobsCount(where) 
  wjc_cancel && wjc_cancel();
  const request = axios.get(`/api/user/report/comms/matrix/upload/count/format/json?quiet=1&where=` + JSON.stringify(where), 
    cancelToken: new CancelToken(function executor(c) 
        // An executor function receives a cancel function as a parameter
        wjc_cancel = c;
      
  );
  return 
    type: FETCH_WORKERJOBS_COUNT,
    payload: request
  ;

【讨论】:

我如何从我的组件访问let wj_cancel, wjc_cancel; @shorif2000 这个想法是fetchWorkerJobsCountfetchWorkerJobs 在您尝试进行新的提取时会自行调用它。 哦...这在任何地方都没有写得很清楚。让我感到困惑。 @shorif2000 或者,您可以导出这两个变量并将它们导入以在您的组件中使用。 export const FETCH_WORKERJOBS_COUNT_CANCEL = wjc_cancel; 导出另一个变量,其初始值为wjc_cancel,即undefined。您需要直接导出wjc_cancelexport wj_cancel;【参考方案2】:

下面是可以使用的代码:

// get info in component
useEffect(() => 
    const cancelToken = customAxios.CancelToken.source();
    dispatch(fetchStream(match.params.id, cancelToken.token));

    return () => 
        cancelToken.cancel(`Cancel fetchStream $match.params.id`)
    
, []);

// where fetchStream in store/actions/streams.js
export const fetchStream = (id, cancelToken) => async dispatch => 
    try 
        const data: stream = await axios.get(`/streams/$id`, 
            cancelToken
        );

        dispatch(
            type: FETCH_STREAM,
            payload: stream
        )
     catch (e) 
        console.log("fetchStream get error ", e);
    
;

【讨论】:

以上是关于如何在反应中使用redux取消以前的axios的主要内容,如果未能解决你的问题,请参考以下文章

redux中如何使用axios获取api项?

取消路由更改请求 (React/Redux/Axios)

在 useEffect 挂钩中使用 axios 取消令牌时如何修复失败的测试

Redux axios 请求取消

如何使用 redux-axios-middleware 测试 Redux 异步操作

反应 redux,thunk 完成事件过早发生