Flux waitFor() and async operation, how to model.

swennemen picture swennemen · Jan 5, 2015 · Viewed 7k times · Source

I'm using pouchDB as a local database for an app. I want to query the results from PouchDB and load this into React.js. However, even though I'm using the waitFor() method the results of PouchDB query return too late. I think I don't understand the use of waitFor() correct, maybe someone can shed a light on it.

I have two stores, the DbStore that retrieves data from the datbase. And the FileExplorerStore this store is used by my react components.

DbStore.dispatchToken = AppDispatcher.register(function (payload) {

    var action = payload.action;
    var folder = payload.action.folder
    switch (action.type) {

        case 'OPEN_FOLDER':    
            if (folder === 'start') {
                DbStore.init();
            }
            else {
                DbStore.createPath(folder);
            }
            DbStore.emitChange();
            break;
        default:
        // do nothing
    }


    return true;
});

The DbStore has a function LoadFiles that will load the DB files into the _files array. For illustrative purposes I've copied the code below:

loadFiles: function (_path) {
            var fileNames = fs.readdirSync(_path);
            _files = [];


            fileNames.forEach(function (file) {
                console.log(file)
                db.query(function (doc) {
                    emit(doc.name);
                }, {key: "bower.json"}).then(function (res) {
                    _files.push(res.rows[0].key)
                });
            });

 }, 

The FileExplorerStore had a method to retrieve the files from the _files array. Then in the FileExplorerStore I have a getFiles() method, that will retrieve these files. However, this array is always empty because this method will be executed before the array is filled.

FileExplorerStore

FileExplorerStore.dispatchToken = AppDispatcher.register(function (payload) {

var action = payload.action;


switch (action.type) {

    case 'OPEN_FOLDER':
        AppDispatcher.waitFor([DbStore.dispatchToken]);

        FileExplorerStore.emitChange();
        break;
    default:
    // do nothing
}


return true;
});

In react.js the getInitialState function will call the getFiles() function from the FileExplorerStore to display the files.

How can I fix this or model this in a better way?

Answer

ChinKang picture ChinKang · Jan 6, 2015

The waitFor in the dispatcher released by the Facebook team was not designed for that (at least the release on Sep 11, 2014), it just make sure the dispatchToken (which passed to waitFor) was executed and returned, and then it will starts executing the next registered callback.

So in your case this is somehow the correct expected behaviour.

What i will do is separate the action into two parts. First is fetching, second is OPEN_FOLDER as in FileExplorerStore. Assuming the DBfetch action named DB_FETCH, this will trigger your database and then get the data into _files, in the fetch success callback, trigger an action to the OPEN_FOLDER. For the trigger point, it is depends on you how you want to design it, i would have the third action named INIT_OPEN_FOLDER which trigger the DB_FETCH, then show the loading indicator to the UI, and finally when get the emit from OPEN_FOLDER, only display the data