Reactjs 如何在Redux和React.js中使用异步多请求加载程序

Reactjs 如何在Redux和React.js中使用异步多请求加载程序,reactjs,redux,react-redux,Reactjs,Redux,React Redux,我试图在数据尚未提取时设置加载器。如果数据只上传一个,这个场景就很容易了(这里的逻辑是:将标志设置为isFetching为true,当从redux接收时将其设置为false)。但我的情况有点不同。我想多次获取数据以更新日历组件。所有这些都是通过axios软件包的redux完成的 看起来是这样的: import React, { Component } from 'react'; import Calendar from 'react-calendar'; import ChooseHour fr

我试图在数据尚未提取时设置加载器。如果数据只上传一个,这个场景就很容易了(这里的逻辑是:将标志设置为isFetching为true,当从redux接收时将其设置为false)。但我的情况有点不同。我想多次获取数据以更新日历组件。所有这些都是通过axios软件包的redux完成的

看起来是这样的:

import React, { Component } from 'react';
import Calendar from 'react-calendar';
import ChooseHour from './ChooseHour';
import { connect } from 'react-redux';
import * as actions from '../actions';

class Calendario extends Component {
    state = { showHours: false, disabledDates: null}

    componentDidMount() {
        const { chosenRoom } = this.props;
        const date = new Date();
        const reqMonth = date.getMonth() + 1;
        const reqYear = date.getFullYear();
        this.props.activeMonthYearToPass({reqMonth, reqYear, chosenRoom});
    }

    onChange = date => this.setState({ date }, () => {
            const { chosenRoom, isBirthday } = this.props;
            const year = date.getFullYear();
            const month = date.getMonth() + 1;
            const day = date.getDate();
            const fullDate = `${year}/${month}/${day}`;
            const roomAndDayObj = {fullDate, chosenRoom, isBirthday};
            this.props.sendRoomAndDay(roomAndDayObj); 
        }
    );

    onClickDay(e) {
        const { chosenRoom } = this.props;
        !chosenRoom ? this.setState({ errorMsg: "Wybierz pokój", showHours: false}) :
        this.setState({ showHours: true, errorMsg:'' });
    } 

    passActiveDate(activeDate) {
        const { chosenRoom } = this.props;
        const reqMonth = activeDate.getMonth() + 1;
        const reqYear = activeDate.getFullYear();
        this.setState({ pending: true},
            () => this.props.activeMonthYearToPass({reqMonth, reqYear, chosenRoom})
        );
        this.props.passDateDetails({reqMonth, reqYear});
    }

    render() { 
        const { fullyBookedDays, isBirthday } = this.props;
        const { errorMsg, pending } = this.state;
        return ( 
        <div>
            <div className="calendarsCont">
                    <Calendar
                        onChange={this.onChange}
                        onClickDay={(e) => this.onClickDay(e)}
                        onActiveDateChange={({ activeStartDate }) => this.passActiveDate(activeStartDate)}
                        value={this.state.date}
                        locale="pl-PL"
                        tileDisabled={({date, view}) =>
                            (view === 'month') && 
                            fullyBookedDays && fullyBookedDays.fullyBooked.some(item =>
                            date.getFullYear() === new Date(item).getFullYear() &&
                            date.getMonth() === new Date(item).getMonth() -1 &&
                            date.getDate() === new Date(item).getDate()
                            )}
                    /> 
                }
            </div> 
            <p style={{color: 'red'}}>{errorMsg}</p>
            <div>
                {this.state.showHours ? 
                    <ChooseHour chosenDay={this.state.date} chosenRoom={this.props.chosenRoom} isBirthday={isBirthday}/> : 
                null}
            </div>
        </div>
        )
    }
}

function mapStateToProps({fullyBookedDays}){
    return {
        fullyBookedDays,
    }
}

export default connect (mapStateToProps, actions)(Calendario);
My reducer在完成axios请求时添加isFetching标志(存储已更新):

组件看起来是这样的:

import React, { Component } from 'react';
import Calendar from 'react-calendar';
import ChooseHour from './ChooseHour';
import { connect } from 'react-redux';
import * as actions from '../actions';

class Calendario extends Component {
    state = { showHours: false, disabledDates: null}

    componentDidMount() {
        const { chosenRoom } = this.props;
        const date = new Date();
        const reqMonth = date.getMonth() + 1;
        const reqYear = date.getFullYear();
        this.props.activeMonthYearToPass({reqMonth, reqYear, chosenRoom});
    }

    onChange = date => this.setState({ date }, () => {
            const { chosenRoom, isBirthday } = this.props;
            const year = date.getFullYear();
            const month = date.getMonth() + 1;
            const day = date.getDate();
            const fullDate = `${year}/${month}/${day}`;
            const roomAndDayObj = {fullDate, chosenRoom, isBirthday};
            this.props.sendRoomAndDay(roomAndDayObj); 
        }
    );

    onClickDay(e) {
        const { chosenRoom } = this.props;
        !chosenRoom ? this.setState({ errorMsg: "Wybierz pokój", showHours: false}) :
        this.setState({ showHours: true, errorMsg:'' });
    } 

    passActiveDate(activeDate) {
        const { chosenRoom } = this.props;
        const reqMonth = activeDate.getMonth() + 1;
        const reqYear = activeDate.getFullYear();
        this.setState({ pending: true},
            () => this.props.activeMonthYearToPass({reqMonth, reqYear, chosenRoom})
        );
        this.props.passDateDetails({reqMonth, reqYear});
    }

    render() { 
        const { fullyBookedDays, isBirthday } = this.props;
        const { errorMsg, pending } = this.state;
        return ( 
        <div>
            <div className="calendarsCont">
                    <Calendar
                        onChange={this.onChange}
                        onClickDay={(e) => this.onClickDay(e)}
                        onActiveDateChange={({ activeStartDate }) => this.passActiveDate(activeStartDate)}
                        value={this.state.date}
                        locale="pl-PL"
                        tileDisabled={({date, view}) =>
                            (view === 'month') && 
                            fullyBookedDays && fullyBookedDays.fullyBooked.some(item =>
                            date.getFullYear() === new Date(item).getFullYear() &&
                            date.getMonth() === new Date(item).getMonth() -1 &&
                            date.getDate() === new Date(item).getDate()
                            )}
                    /> 
                }
            </div> 
            <p style={{color: 'red'}}>{errorMsg}</p>
            <div>
                {this.state.showHours ? 
                    <ChooseHour chosenDay={this.state.date} chosenRoom={this.props.chosenRoom} isBirthday={isBirthday}/> : 
                null}
            </div>
        </div>
        )
    }
}

function mapStateToProps({fullyBookedDays}){
    return {
        fullyBookedDays,
    }
}

export default connect (mapStateToProps, actions)(Calendario);
import React,{Component}来自'React';
从“反应日历”导入日历;
从“/ChooseHour”导入ChooseHour;
从'react redux'导入{connect};
将*作为动作从“../actions”导入;
类Calendario扩展组件{
状态={showHours:false,disabledDates:null}
componentDidMount(){
const{chosenRoom}=this.props;
const date=新日期();
const reqMonth=date.getMonth()+1;
const reqYear=date.getFullYear();
this.props.activeMonthYearToPass({reqMonth,reqYear,chosenRoom});
}
onChange=date=>this.setState({date},()=>{
const{chosenRoom,isBirthday}=this.props;
const year=date.getFullYear();
const month=date.getMonth()+1;
const day=date.getDate();
const fullDate=`${year}/${month}/${day}`;
const roomAndDayObj={fullDate,chosenRoom,isBirthday};
this.props.sendRoomAndDay(roomAndDayObj);
}
);
一天(e){
const{chosenRoom}=this.props;
!chosenRoom?this.setState({errorMsg:“Wybierz pokój”,showHours:false}):
this.setState({showHours:true,errorMsg:''});
} 
passActiveDate(活动日期){
const{chosenRoom}=this.props;
const reqMonth=activeDate.getMonth()+1;
const reqYear=activeDate.getFullYear();
this.setState({pending:true},
()=>this.props.activeMonthYearToPass({reqMonth,reqYear,chosenRoom})
);
this.props.passDateDetails({reqMonth,reqYear});
}
render(){
const{fullyBookedDays,isBirthday}=this.props;
const{errorMsg,pending}=this.state;
报税表(
本.onClickDay(e)}
OnActivatedTechRange={({activeStartDate})=>this.passActivateDate(activeStartDate)}
值={this.state.date}
locale=“pl”
tileDisabled={({date,view})=>
(视图=‘月份’&&
fullybookedday&&fullybookedday.fullyBooked.some(项=>
date.getFullYear()==新日期(项目).getFullYear()&&
date.getMonth()==新日期(项目).getMonth()-1&&
date.getDate()==新日期(项目).getDate()
)}
/> 
}

{errorMsg}

{this.state.showHours? : 空} ) } } 函数mapstatetops({fullyBookedDays}){ 返回{ 十足的书基达, } } 导出默认连接(MapStateTrops,actions)(Calendario);
因此,新值将多次来自axios请求。 在这种情况下你会采取什么策略


谢谢大家!

每当有多个抓取请求,或者甚至有多个操作指示正在发生异步并且需要存储在状态的一部分时,我都会使用计数器:

export default function(state = {fetchCount: 0}, action){
    switch(action.type){
        case FETCHING_THING:
            return Object.assign({}, state, {
                fetchCount: state.fetchCount + 1
            })
        case FETCHING_THING_DONE:
            return Object.assign({}, state, {
                fetchCount: state.fetchCount - 1,
                fullyBooked: action.payload
            }
        default:
            return state;
    }
}
然后,您可以在MapStateTrops中选中
fetchCount>0

function mapStateToProps({fullyBookedDays, fetchCount}){
    return {
        fullyBookedDays,
        isLoading: fetchCount > 0
    }
}

请以下面的示例为例,Redux thunk风格的操作用于包装多个axios请求并将其全部分派

//axios call2
函数getData1(){
返回axios.get('/data1');
}
//axios call2
函数getData2(){
返回axios.get('/data2');
}
//redux thunk动作创建者
函数getFullData(){
返回(调度,获取状态)=>{
所有([getData1(),getData2()]))
.然后(axios.spread)(函数(acct,perms){
//调用普通操作创建者
分派(fetchData1())
分派(fetchData2())
}));
};
}
//正常操作创建者
函数fetchData1(数据)
{
返回{type:“FETCH_DATA1”,有效负载:data}
}
//正常操作创建者
函数fetchData2(数据)
{
返回{type:“FETCH_DATA2”,有效负载:data}
}
//减速器1:
函数缩减器1(状态=默认状态,操作){
返回Object.assign({},{…state,data:action.payload,isFetching:false})
}
//还原剂2:
函数约简器2(状态=默认状态,操作){
返回Object.assign({},{…state,data:action.payload,isFetching:false})
}
//组成部分:
mapStateToProps=函数(状态){
返回{
data1:state.data1.data,
data2:state.data2.data,
isFetching1:state.data1.isFetching,
isFetching2:state.data2.isFetching
}
}
从“React”导入React,{Component};
类MyComponent扩展组件{
render(){
返回(!data1&&isFetching1)| |(!data2&&isFetching2)?:
}
}

connect(MapStateTops)(MyComponent)
OP已经使用了这种技术,它不能处理多个请求,因为当一个请求完成时,当第二个请求仍在运行时,它会将isFetching标志变为false。为什么不将这些axios请求包装在redux thunk actionCreator中,其中可以将多个请求与axios.all组合,并且只为所有请求准备一个标志(isFetching)(在reducer中执行)触发这两个请求的动作不一定相同。如果两个单独的操作触发了不同的axios请求,那么您的组件仍然需要知道仍在提取的内容。例如,当我可以在w处添加和删除附件时,我使用组件