kjda / ReactFlux

A library implementing React-Flux data flow design pattern + Code Generation
MIT License
66 stars 12 forks source link

Events somehow disappear #2

Closed LKay closed 9 years ago

LKay commented 9 years ago

I came across weird behavior and it seems like a bug but could find a solution for this. How to reproduce:

For some reason the event to emit becomes undefined at some point instead of function. The code which fails to execute is:

    /**
      *
      * @param {String} evt
      */
    emit: function(evt){
      if( typeof this._events[evt] == 'undefined' ){
        return;
      }
      var args = Array.prototype.slice.call(arguments, 1);
        _forEach(this._events[evt], function(listner){
          listner.apply(null, args)
        });
    },

The listner becomes undefined so apply can't be called. I tried debug it to find the cause but couldn't.

kjda commented 9 years ago

Hi, I could not repeat this! would be great if you could provide me with a sample code that does not work.

Here is my test code

var constants = ReactFlux.createConstants([
    'TEST'
], 'NS');

var actions = ReactFlux.createActions({
    test: [constants.TEST, function(){
        console.log("test.action");
    }]
});

var store = ReactFlux.createStore({

});

store.addActionHandler(constants.TEST, {
    before: function(){
        console.log("test.before")
    },
    after: function(){
        console.log("test.after")
    },
    success: function(){
        console.log("test.success")
    }
});

setInterval(function(){
    actions.test();
}, 5000);

output:

test.before
test.action
test.success
test.after
LKay commented 9 years ago

All right! This is my sample code to reproduce this, a little simplified and shows the first case with setTimeout:

Constants

var threadsConstants = ReactFlux.createConstants([
    "LOAD"
], "THREADS");

Actions

var threadsActions = ReactFlux.createActions({
    load: [threadsConstants.LOAD, function (options) {
        return $.ajax(options);
    }]
});

Store

var threadsStore = ReactFlux.createStore({
    getInitialState: function () {
        return {
            loading: false,
            collection: null
        };
    }
}, [
    [threadsConstants.LOAD, function onLoad (payload) {
        this.setState({
            loading: true
        });
    }],
    [threadsConstants.LOAD_DONE, function handleLoadDone (payload) {
        var threads = payload.threads;
        this.setState({
            collection: threads
        });
    }],
    [threadsConstants.LOAD_ALWAYS, function handleLoadAlways (payload) {
        this.setState({
            loading: false
        });
    }]
]);

Component

var Threads = React.createClass({
    mixins: [
        threadsStore.mixin()
    ],

    getFetchOptions: function () {
        return {
            url: "/api/threads",
            data: {
                limit: this.props.limit,
                offset: this.props.offset,
            }
        };
    },

    getStateFromStores: function () {
        return {
            threads: threadsStore.state
        };
    },

    waiter: null,

    delayedLoad: function () {
        clearTimeout(this.waiter);
        this.waiter = setTimeout((function (cmp) {
            return function () { threadsActions.load(cmp.getFetchOptions()); };
        })(this), 1000)
    }

    componentDidMount: function () {
        threadsActions.load(this.getFetchOptions());
    },

    componentDidUpdate: function (props, states) {
        this.delayedLoad();
    },

    render: function () {
        return (
                <ThreadsList threads={this.state.threads.get("collection")} />
        );
    }

});
kjda commented 9 years ago

Your code works here without a problem.. I could think of only one thing which may cause the problem: You are not using the default constant suffixes (_SUCCESS, _FAIL, _AFTER).. Did you configure the constant generator to do so?

in your case you should have the following in your bootstraping:

ReactFlux.configs.constants.setSuccessSuffix('DONE');
ReactFlux.configs.constants.setAfterSuffix('ALWAYS');
ReactFlux.configs.constants.setFailSuffix('ERROR');

Are you using the latest version of the library?

another issue: the way you are setting timeout in "delayedLoad" may cause some errors. if your component gets unmounted the timeout will still exist, which is not what you want.. you should do clearTimeout(this.waiter) in componentWillUnmount