0

I am using the flux architecture with reactjs. I am trying to implement control over displaying a spinjs spinner.

This is my component view that is using the spinner:

var ItemListing = React.createClass({
    render: function(){

        if (this.state.loading === true) { 
            return (
                <div className="pill-pane active item-list-pane">
                        <LoadSpin />
                </div>
            )
        }

        // .. more non-related logic here

        return (
            <div className="pill-pane active item-list-pane">
                { items }
                <Paginator
                    paginationClickHandler={ this.paginationClickHandler }
                    offset={ offset }
                    limit={ limit }
                    store={ AppStore }
                />
            </div>
        );
    },

    getInitialState: function(){
        return {
            items: AppStore.getAssetDetails().assetList
        };
    },

    componentWillMount: function(){
        AppStore.addChangeListener(this.changeHandler);
        AppStore.addChangeListener(this.toggleActivity);
    },

    componentDidMount: function(){
        this.setState({loading: false});
        AppActions.queryAssets();
    },

    toggleActivity: function() {
        this.setState({loading: true});
    }
});

As shown in componentWillMount I add this.toggleActivity which ultimately sets the loading state to true. Then in componentDidMount I set the loading state to false. But for some reason my spinner remains spinning indefinitely. That is, it never gets set to false when laid out like this. How can I change this so that it will change to false?

Edit - added AppStore.js as requested:

"use strict";

var AppDispatcher = require('../AppDispatcher');
var assetConstants = require('../constants/AssetConstants');
var EventEmitter = require('events').EventEmitter;

var CHANGE_EVENT = 'assetChange';

// Application State
var _assetDetails = {
    assetList: [],
    requestStatus: undefined,
    totalCount: 0
};

var _queryProgress;

var AppStore = $.extend({}, EventEmitter.prototype, {
    emitChange: function(){
        this.emit(CHANGE_EVENT);
    },

    addChangeListener: function(callback){
        this.on(CHANGE_EVENT, callback);
    },

    removeChangeListener: function(callback){
        this.removeListener(CHANGE_EVENT, callback);
    },

    getTotalCount: function(){
        if(_assetDetails.meta){
            return _assetDetails.meta.total_count;
        }

        return 0;
    },

    getAssetDetails: function(){
        return _assetDetails;
    },

    getRequestStatus: function(){
        return _assetDetails.requestStatus;
    },

    getQueryProgress: function(){
        return _queryProgress;
    },

    dispatcherIndex: AppDispatcher.register(function(payload){
        var action = payload.action.actionType;

        if(payload.source === "ASSET_ACTION"){
            switch(action){ // eslint-disable-line default-case
                case assetConstants.QUERY_ASSETS:
                    _assetDetails = payload.action.assetDetails;
                    break;

                case assetConstants.QUERY_PROGRESS:
                    _queryProgress = payload.action.progress;
                    break;
            }

            AppStore.emitChange();

            _assetDetails.requestStatus = undefined;
        }
        return true;
    })
});

module.exports = AppStore;

Re-edit added AppActions.js:

"use strict";
var assetConstants = require('../constants/AssetConstants');
var AppDispatcher = require('../AppDispatcher');
var config = require('../../config');
var ITEM_V2_MAP = require('./apiRemapping').ITEM_V2_MAP;
var getRemappedAssets = require('./apiRemapping').getRemappedAssets;

var AssetActions = {
    queryAssets: function(filters){
        var assetDetails;

        $.ajax({
            method: "GET",
            url: config.endpoints.itemAPIV2,
            contentType: "application/json",
            dataType: "json",
            data: filters,
            beforeSend: function(){
                AppDispatcher.handleAssetAction({
                    actionType: assetConstants.QUERY_PROGRESS,
                    progress: "querying"
                });
            },
            success: function(data) {
                var remappedAssets = getRemappedAssets(
                    data.objects, ITEM_V2_MAP
                );

                assetDetails = {
                    assetList: remappedAssets,
                    currentFilters: filters,
                    meta: data.meta
                };
            },
            error: function() {
                assetDetails = {
                    assetList: [],
                    totalCount: 0
                };
            },
            complete: function(data) {
                assetDetails.requestStatus = data.status;

                AppDispatcher.handleAssetAction({
                    actionType: assetConstants.QUERY_ASSETS,
                    assetDetails: assetDetails
                });

                AppDispatcher.handleAssetAction({
                    actionType: assetConstants.QUERY_PROGRESS,
                    progress: "finished querying"
                });
            }
        });
    }
};

module.exports = AssetActions;
ApathyBear
  • 9,057
  • 14
  • 56
  • 90
  • Are you doing server-side rendering by chance? – Matthew Herbst Aug 21 '15 at 20:35
  • I have ajax actions that populate my main store. Then I pull from said store. Is that what you mean by server side rendering? – ApathyBear Aug 21 '15 at 20:42
  • No, I meant actually running the `render` and such on the server and then just serving up the HTML to the client. Can you show us your `AppStore` code by chance? – Matthew Herbst Aug 21 '15 at 20:44
  • @MatthewHerbst I believe I am using client-side rendering. And I have updated the question to include the AppStore – ApathyBear Aug 21 '15 at 20:54
  • `AppStore.addChangeListener(this.toggleActivity);` you are never (afaik) removing this listener, so it is called and sets loading to true every time. – lemieuxster Aug 21 '15 at 21:04
  • @lemieuxster Ahh, good point. So where in the components life cycle should I place `AppStore.removeChangeListener(this.toggleActivity);`? . I placed it in componentDidMount at the end but that seems to still not turn off the spinner. – ApathyBear Aug 21 '15 at 21:14

1 Answers1

0

Placing your AppStore.addChangeListener(this.toggleActivity); in the componentWillUnmount() lifecycle should solve the issue.

mightwork
  • 53
  • 7
  • I tried this, but it doesn't seem to work. I also tried adding `this.setState({loading: false});` in `componentWillUnmount` with it and it still doesn't work. – ApathyBear Aug 21 '15 at 22:52
  • Is it possible that `AppActions.queryAssets();` is firing an event which results in `toggleActivity` to be executed again ? Moreover in Flux you shouldn't modify state directly from the app but use a store instead. – mightwork Aug 21 '15 at 22:58
  • No, `AppActions.queryAssets();` is not doing anything except for executing an AJAX call. I have provided it in my original question. And yes I agree it should be in the store, but given a ReactJs lifecycle, it should work as is, but isn't. – ApathyBear Aug 22 '15 at 06:48