redux-thunk:暂停组件执行直到Action Creator完成
我几周来一直在努力解决这个问题。我终于放弃了并在此寻求帮助,因为我显然没有做正确的事情。我有一个使用redux和redux-thunk的React.js应用程序。我只是试图让我的组件容器启动数据加载,但是直到数据从提取请求返回时才会呈现。我知道这看起来很简单。以下是我所做的:
I've been struggling with this problem for several weeks now. I'm finally throwing in the towel and asking for help on this because I'm clearly not doing something right. I have a React.js app that is using redux and redux-thunk. I'm simply trying to get my Component Container to initiate the loading of data, but not render until the data comes back from the fetch request. Seems simple enough I know. Here is what I've done:
容器组件
'use strict';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchActivePlayer } from '../actions/index';
import PlayerDetails from '../components/players/player-detail';
import Spinner from '../components/common/spinner/index';
import store from '../store';
export default class PlayerDetailContainer extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.fetchActivePlayer(this.props.params.player_slug)
}
render() {
if (!this.props.activePlayer.activePlayer) {
return (
<Spinner text="Loading..." style="fa fa-spinner fa-spin" />
);
}
return (
<PlayerDetails
player={ this.props.activePlayer.activePlayer }
/>
);
}
}
function mapStateToProps(state) {
return {
activePlayer: state.activePlayer
}
}
export default connect(mapStateToProps, { fetchActivePlayer })(PlayerDetailContainer);
行动创作者
export function fetchActivePlayer(slug) {
return (dispatch, getState) => {
return axios.get(`${ROOT_URL}/players/${slug}`)
.then(response => {
dispatch({
type: FETCH_ACTIVE_PLAYER,
payload: response
})
})
.catch(err => {
console.error("Failure: ", err);
});
};
}
商店
'use strict';
import React from 'react';
import { browserHistory } from 'react-router';
import { createStore, applyMiddleware } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import reducers from './components/reducers/index';
const createStoreWithMiddleware = applyMiddleware(
thunk,
promise,
routerMiddleware(browserHistory)
) (createStore);
export default createStoreWithMiddleware(reducers);
路线
export default (
<Route path="/" component={ App }>
<IndexRoute component={ HomePage } />
<Route path="players/:player_slug" component={ PlayerContainer } />
<Route path="/:player_slug" component={ PlayerContainer } />
</Route>
);
以下是我用于所有内容的版本:
react = 0.14.7
react-redux = 4.4.1
redux-thunk = 0.5.3
Here are the versions I'm using for everything: react = 0.14.7 react-redux = 4.4.1 redux-thunk = 0.5.3
当我运行时,我没有收到任何错误,但它是清除我的动作创建者正在解雇但我的组件容器继续而不是等待创建者完成。就像我说的那样,我确信我必须遗漏一些非常简单的东西,但我似乎无法弄清楚那是什么。
When I run this, I don't receive any errors but it's clear that my action creator is firing but my component container continues instead of waiting for the creator to finish. Like I said, I'm sure I must be missing something really simple but I can't seem to figure out what that is.
提前谢谢你。任何帮助将不胜感激。
Thank you in advance. Any help would be greatly appreciated.
- 您在componentWillMount中的操作(获取)是异步,组件不会等待。
- 通常,当您获取某些数据时,您想知道获取过程的状态。喜欢isfetching以显示加载器,成功和失败以显示错误。
- 您可以使用这些状态来加载/挂载/启动组件,直到Action Creator完成。
- your action(fetch) in componentWillMount is async ,component will not wait.
- Usually when you fetch some data , you want to know about statuses of fetching process. like "isfetching" in order to showing loader, success and failure in order to showing error.
- You can use these statuses to not load/mount/launch component, Until Action Creator Completes.
因此,你应该组织你的redux部件:
Thus, you should organize your redux parts somthing like that:
州
activePlayer:{
data:data,
isFetching: true/false,
error:""
}
操作
export const fetchActivePlayer = slug => dispatch =>{
dispatch({
type: 'FETCH_ACTIVE_PLAYER_REQUEST',
isFetching:true,
error:null
});
return axios.get(`${ROOT_URL}/players/${slug}`)
.then(response => {
dispatch({
type: 'FETCH_ACTIVE_PLAYER_SUCCESS',
isFetching:false,
payload: response
});
})
.catch(err => {
dispatch({
type: 'FETCH_ACTIVE_PLAYER_FAILURE',
isFetching:false,
error:err
});
console.error("Failure: ", err);
});
};
reducer
const initialState = {data:null,isFetching: false,error:null};
export const actionPlayer = (state = initialState, action)=>{
switch (action.type) {
case 'FETCH_ACTIVE_PLAYER_REQUEST':
case 'FETCH_ACTIVE_PLAYER_FAILURE':
return { ...state, isFetching: action.isFetching, error: action.error };
case 'FETCH_ACTIVE_PLAYER_SUCCESS':
return { ...state, data: action.payload, isFetching: action.isFetching,
error: null };
default:return state;
}
};
那么您的组件可能看起来像这样(硬编码)
class PlayerDetailContainer extends Component {
componentWillMount() {
this.props.fetchActivePlayer(this.props.params.player_slug)
}
render() {
if (this.props.isFetching) {
return <Spinner text="Loading..." style="fa fa-spinner fa-spin" />
}else if (this.props.error) {
return <div>ERROR {this.props.error}</div>
}else {
return <PlayerDetails player={ this.props.data } />
}
}
}
const mapStateToProps = state =>({
isFetching: state.activePlayer.isFetching,
data: state.activePlayer.data,
error: state.activePlayer.error,
})
我不知道你的应用程序是什么样的。此示例的目标是说明方法。