redux-thunk:暂停组件执行直到Action Creator完成

时间:2016-06-27 23:17:58

标签: javascript reactjs redux react-redux redux-thunk

我几周来一直在努力解决这个问题。我终于放弃了并在此寻求帮助,因为我显然没有做正确的事情。我有一个使用redux和redux-thunk的React.js应用程序。我只是试图让我的组件容器启动数据加载,但是直到数据从提取请求返回时才会呈现。我知道这看起来很简单。这就是我所做的:

容器组件

'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>
);

以下是我用于所有内容的版本: 反应= 0.14.7 react-redux = 4.4.1 redux-thunk = 0.5.3

当我运行它时,我没有收到任何错误,但很明显我的动作创建者正在解雇,但我的组件容器仍在继续,而不是等待创建者完成。就像我说的那样,我确信我必须遗漏一些非常简单的东西,但我似乎无法弄清楚那是什么。

提前谢谢你。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:7)

  1. componentWillMount中的action(fetch)为异步,组件不会等待。
  2. 通常,当您获取某些数据时,您想了解获取过程的状态。喜欢“isfetching”以显示加载器,成功和失败以显示错误。
  3. 您可以使用这些状态来加载/装载/启动组件,直到Action Creator完成。
  4. 因此,你应该组织你的redux部分:

    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,
    })
    

    我不知道您的应用是怎样的。此示例的目标是说明方法。