在componentDidMount
中调用mapDispatchToProps
函数时怎么会出现,
mapStateToProps
totalDoctorCount:state.doctors.totalDoctorCount
不会总是按时加载,我会在 console.log("this .props.totalDoctorCount: "+this.props.totalDoctorCount );
.
我知道这是 async
的本质,但有没有办法解决它,我在这里做错了什么。
完整代码:
医生行动
export function getDoctors(filterType){
return function(dispatch){
axios.get("/api/doctors/"+filterType)
.then(function(response){
dispatch({type:"GET_DOCTORS",payload:response.data});
})
.catch(function(err){
dispatch({type:"GET_DOCTORS_REJECTED",payload:err});
})
}
}
export function getTotalDoctors(){
return function(dispatch){
axios.get("/api/getTotalDoctors/")
.then(function(response){
dispatch({type:"TOTAL_DOCTORS",payload:response.data});
console.log(response.data);
})
.catch(function(err){
//console.log(err);
dispatch({type:"TOTAL_DOCTORS_REJECTED",payload:"there was an error rortal doctors"});
})
}
}
医生 reducer
export function doctorsReducers(state={
doctors:[],
}, action){
switch(action.type){
case "GET_DOCTORS":
// return the state and copy of boos array from state
return {...state,doctors:[...action.payload]}
break;
case "TOTAL_DOCTORS":
// return the state and copy of boos array from state
return {
...state,
totalDoctorCount:action.payload
}
break;
}
return state;
}
服务器接口(interface)
app.get('/doctors/:filterType',function(req,res){
let filterType = req.params.filterType;
var query = {};
if(filterType == "dateCreated"){
query = {date_created: 'desc'};
}else if(filterType == "dateUpdated"){
query = {date_updated: 'desc'};
}
Doctors.find({}).sort(query).limit(3).exec(function(err,doctors){
if(err){
throw err;
}
res.json(doctors);
});
});
app.get('/getTotalDoctors',function(req,res){
Doctors.count({}, function(err, count){
if(err){
throw err;
}
res.json(count);
});
});
组件
class MainAdmin extends React.Component{
constructor(){
super();
this.state = {
selected_filter:"dateCreated"
};
}
openAddDoctorModal = () => {
this.setState({AddDoctorModal:true});
}
closeAddDoctorModal = () => {
this.setState({AddDoctorModal:false});
}
componentDidMount(){
this.props.getTotalDoctors();
this.props.getDoctors(this.state.selected_filter);
}
loadPage = (pageNum) => {
//alert(pageNum);
this.props.loadPage(pageNum,this.state.selected_filter);
}
render(){
const doctorsList = this.props.doctors.map(function(doctorsArr){
return(
<Col xs={12} sm={12} md={12} key={doctorsArr._id}>
<DoctorsItem
_id = {doctorsArr._id}
doc_fname = {doctorsArr.doc_fname}
doc_lname = {doctorsArr.doc_lname}
/>
</Col>
)
});
//const lengthPage = parseInt(this.props.totalDoctorCount/3);
console.log("this.props.totalDoctorCount2: "+this.props.totalDoctorCount );
const pages = parseInt(this.props.totalDoctorCount/3, 10);
console.log("pages: "+pages );
const pageNums = [...Array(pages)].map((pageNum, i) => {
return(
<Col xs={2} sm={2} md={2} key={i+1}>
<Button onClick={() => this.loadPage(i+1)} bsStyle="success" bsSize="small">
{i+1}
</Button>
</Col>
)
});
return(
<Well>
<Row style={{marginTop:'15px'}}>
{doctorsList}
</Row>
<Row style={{marginTop:'15px'}}>
{pageNums}
</Row>
</Well>
)
}
}
function mapStateToProps(state){
return{
doctors: state.doctors.doctors,
totalDoctorCount:state.doctors.totalDoctorCount
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({
getDoctors:getDoctors,
loadPage:loadPage,
getTotalDoctors:getTotalDoctors
},dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(MainAdmin);
最佳答案
有几种方法可以处理这个问题,但您必须首先了解如何处理影响您的 dom 的异步操作。
每当一个组件挂载(并且取决于你如何设置你的应用程序,每当对 Prop ,状态等进行更改)时,它的渲染函数就会被调用。在您的示例中,组件安装,然后向服务器请求医生列表,调用 render()
,然后从服务器接收医生列表。换句话说,在它调用 render 方法时,它还没有收到来自 axios 调用的医生列表。
如果您理解所有这些,我们深表歉意。现在了解为什么 this.props.totalDoctorCount
返回 undefined
:您的应用程序的 state.totalDoctorCount
直到函数 getTotalDoctors< 才被定义
解析(即从服务器收到回复)。您可以通过在 defaultState
中将 totalDoctorCount
定义为 0
(您将医生定义为空数组)来解决此问题。
另一方面,在服务器及时响应之前,你真的希望用户看到/认为总共有0
个医生吗?这可能是考虑加载组件的好机会。我喜欢做的是在 render()
下面,检查是否存在你需要遍历的任何列表,如果它是空的,你可以返回一个 LoadingComponent
(你可以自己制作并在任何需要加载的地方使用它)。
这本身是不够的,因为如果您实际上没有任何医生,您不希望页面无限期地加载,所以这个 LoadingComponent
应该只在函数出现时出现检索它所关注的列表仍然是“获取”。因此,也许您可以实现在获取之前、获取响应之后以及出现错误时调用的三个操作。
概述:
1) MainAdmin 安装。
2) GetDoctors
和 GetTotalDoctors
被调用。
3) 一个新 Action isFetching
被调用,留下你的状态:
{
doctors: [],
totalDoctors: 0, //assuming you have added this to defaultState
isFetchingDoctors: true
}
4) MainAdmin
调用 render()
。
5) 由于 state.doctors 为空且 state.isFetchingDoctors
为 true
,MainAdmin.render()
返回您的新 正在加载组件
。
6) 您的服务器使用医生列表和 totalDoctorCount
响应您的 axios 调用(注意:这将在不同时间发生,但为了简单起见,我将它们视为一起发生).
7) 您的成功处理程序使用新的医生列表更新您的状态:
{
doctors: [1, 2, 3],
totalDoctors: 3,
isFetchingDoctors: true
}
8) MainAdmin 调用
render()
因为状态改变了,但是因为 state.isFetchingDoctors
仍然为真,它会仍然显示 LoadingComponent。
8) 您的第二个新操作 isFetched()
被调用,您的状态为:
{
doctors: [1, 2, 3],
totalDoctors: 3,
isFetchingDoctors: false
}
9) MainAdmin
再次调用 render()
,但这次表明它不再加载的条件得到满足,您可以安全地遍历您的列表的医生。
最后一点:您也可以在 GetDoctors
后立即在 reducer 中将 isFetching 设置为 false,但我个人喜欢将异步状态函数分离到它们自己的函数中,以保持每个函数的座右铭函数只负责做一件事。
关于javascript - react redux 异步 mapStateToProps,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47800412/