【问题标题】:React Flux - Handle concurrent action calls avoiding "dispatch in the middle of a dispatch"?React Flux - 处理并发操作调用避免“在调度中间调度”?
【发布时间】:2017-04-12 16:42:56
【问题描述】:

我有一个控制器视图,它需要从两个 API 端点获取初始数据。第一部分是用户身份验证状态,第二部分是项目列表,用于填充菜单。

控制器视图:

import React, { PropTypes } from 'react';
import BaseComponent from '../../Components/Base';
import Menu from '../../Components/App/Menu';
import ItemAction from '../../Actions/Items/ItemAction';
import AuthAction from '../../Actions/Auth/AuthAction';
import ItemStore from '../../Stores/Items/ItemStore';
import AuthStore from '../../Stores/Auth/AuthStore';

class App extends BaseComponent {
    constructor(props) {
        super(props);

        this.state = {};

        this._bind('getAuth', 'getItems');
    }

    componentWillMount() {
        AuthStore.addChangeListener(this.getAuth);
        ItemStore.addChangeListener(this.getItems);
    }

    componentDidMount() {
        AuthAction.check();
        ItemAction.getItems();
    }

    componentWillUnmount() {
        AuthStore.removeChangeListener(this.getAuth);
        ItemStore.removeChangeListener(this.getItems);
    }

    getAuth() {
        this.setState(AuthStore.getState());
    }

    getItems() {
        this.setState(ItemStore.getState());
    }

    render() {
        const { user, items } = this.state;

        const childrenWithProps = React.Children.map(this.props.children,
            (child) => React.cloneElement(child, {
                user: user,
                items: items
            })
        );

        return (
            <div>
                <Menu user={user} items={items}/>
                { childrenWithProps }
            </div>
        );
    }
}

App.propTypes = {
    params: PropTypes.object.isRequired,
    query: PropTypes.object
};

export default App;

物品商店:

import AppStore from '../AppStore';
import AppDispatcher from '../../Dispatcher/AppDispatcher';
import ItemApi from '../../Utils/API/Items/ItemApi';
import ItemConstants from '../../Constants/Items/ItemConstants';

var appState = {
    items: undefined,
    isLoading: false
};


class ItemStore extends AppStore {
    constructor() {
        super();
    }

    reset() {
        appState = {};
    }

    getState() {
        return appState;
    }
}

let storeInstance = new ItemStore();

storeInstance.dispatchToken = AppDispatcher.register(payload => {
    var action = payload.action;

    switch(action.type) {
        case ItemConstants.GET_ITEMS_SUCCESS:
            appState = {
                items: action.data
            };
            break;

        case ItemConstants.GET_ITEMS_FAILURE:
            appState = {
                items: {}
            };
            break;

        default:
            return;
    }

    storeInstance.emitChange();
});

export default storeInstance;

AuthStore:

import AppStore from '../AppStore';
import AppDispatcher from '../../Dispatcher/AppDispatcher';
import AuthApi from '../../Utils/API/Auth/AuthApi';
import AuthConstants from '../../Constants/Auth/AuthConstants';

var appState = {
    user: undefined,
    isLoading: false
};


class AuthStore extends AppStore {
    constructor() {
        super();
    }

    reset() {
        appState = {};
    }

    getState() {
        return appState;
    }
}

let storeInstance = new AuthStore();

storeInstance.dispatchToken = AppDispatcher.register(payload => {
    var action = payload.action;

    switch(action.type) {
        case AuthConstants.GET_USER_SUCCESS:
            appState = {
                user: action.user
            };
            break;

        case AuthConstants.GET_USER_FAILURE:
            appState = {
                user: undefined
            };
            break;

        default:
            return;
    }

    storeInstance.emitChange();
});

export default storeInstance;

授权操作

import AppDispatcher from '../../Dispatcher/AppDispatcher';
import AuthApi from '../../Utils/API/Auth/AuthApi';
import AuthConstants from '../../Constants/Auth/AuthConstants';
import Jwt from '../../Utils/Jwt';

var AuthAction = {
    check: function() {
        if (Jwt.tokenIsValid()) {
            AuthApi.get().then(
                function(response) {
                    AppDispatcher.handleServerAction({
                        type: AuthConstants.GET_USER_SUCCESS,
                        user: response.data
                    });
                }
            )
            .catch(
                function(error) {
                    AppDispatcher.handleServerAction({
                        type: AuthConstants.GET_USER_FAILURE
                    });
                }
            );
        } else {
            AppDispatcher.handleServerAction({
                type: AuthConstants.GET_USER_FAILURE
            });
        }
    }
};

export default AuthAction;

项目操作

import AppDispatcher from '../../Dispatcher/AppDispatcher';
import ItemApi from '../../Utils/API/Items/AuthApi';
import ItemConstants from '../../Constants/Items/ItemConstants';

var ItemAction = {
    getItems: function() {
            ItemApi.getItems().then(
                function(response) {
                    AppDispatcher.handleServerAction({
                        type: ItemConstants.GET_ITEMS_SUCCESS,
                        items: response.data
                    });
                }
            )
            .catch(
                function(error) {
                    AppDispatcher.handleServerAction({
                        type: ItemConstants.GET_ITEMS_FAILURE
                    });
                }
            );
    }
};

export default ItemAction;

我不会包含 API 文件,因为它们只是使用 Axios 对后端进行简单的调用。一切正常,据我所知与 Flux 兼容,但我无法避免偶尔出现“无法在调度过程中调度”的错误。

谁能帮助或告诉我我是否做得对以及我可以做些什么来防止调度错误?

【问题讨论】:

    标签: reactjs reactjs-flux


    【解决方案1】:

    我见过一些添加代码以避免多个同时请求的示例,例如this StackOverflow threadthis blog post。第一个示例防止同时向同一端点发出请求,第二个示例实际上在创建新请求时取消挂起的请求。

    【讨论】:

      猜你喜欢
      • 2016-04-22
      • 2016-01-29
      • 2017-03-13
      • 2015-08-02
      • 2016-04-20
      • 2016-12-03
      • 2017-11-09
      • 2016-06-23
      • 2015-06-29
      相关资源
      最近更新 更多