React Reflux


概念
RefluxはReactのfluxに基づいて作成された一方向データストリームクラスです.Refluxの一方向データストリームパターンは主にactionsとstoresから構成される.例えば、コンポーネントlistにitemが追加されると、actionsのある方法(addItem(data)など)を呼び出し、新しいデータをパラメータとして転送し、イベント機構を通じて、データがstroesに渡され、storesはサーバに要求を開始し、データデータベースを更新することができる.データの更新に成功した後も、やはりイベント機構を通して伝達されるコンポーネントリストの中で、uiを更新します.プロセス全体のドッキングはイベントによって駆動される.このように:
╔═════════╗       ╔════════╗       ╔═════════════════╗
║ Actions ║──────>║ Stores ║──────>║ View Components ║
╚═════════╝       ╚════════╝       ╚═════════════════╝
     ^                                      │
     └──────────────────────────────────────┘
コードはこのように見えます.
var TodoActions = Reflux.createActions([
    'addItem'
]);

var TodoStore = Reflux.createStore({
    items: [1, 2],
    listenables: [TodoActions],
    onAddItem: function (model) {
        $.post('/server/add', {data: model}, function (data) {
            this.items.unshift(data);
            this.trigger(this.items);
        });
    }
});


var TodoComponent = React.createClass({
    mixins: [Reflux.listenTo(TodoStore, 'onStatusChange')],
    getInitialState: function () {
        return {list: []};
    },
    onStatusChange: function () {
        this.setState({list: TodoStore.items});
    },
    render: function () {
        return (
            
{this.state.list.map(function (item) { return

{item}

})}
) } }); React.render(, document.getElementById('container'));
React Fuxと比較
同じ点
  • actions
  • があります.
  • にstores
  • があります.
  • 一方向データストリーム
  • 違い点
  • actionsを内部的に展開することにより、一例のdispatcher
  • が除去される.
  • storesは、actionsの行動をモニターし、煩雑なswitch判断をする必要がない.
  • storesは、相互に傍受することができ、さらなるデータ集約動作を行うことができ、map/reduce
  • と同様である.
  • waitForは、連続的かつ平行なデータストリームによって代替される
  • .
    アクションを作成
    var statusUpdate = Reflux.createAction(options);
    
    戻り値は関数です.この関数を呼び出すと、対応するイベントをトリガします.storeでこの関数を傍受し、対応する処理を行います.
    var addItem = Reflux.createAction();
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (model) {
            console.log(model);
        }
    });
    
    addItem({name: 'xxx'});
    
    複数のアクションを作成
    var TodoActions = Reflux.createActions([
        'addItem',
        'deleteItem'
    ]);
    
    store actionsを傍受する行為:
    var TodoActions = Reflux.createActions([
        'addItem',
        'deleteItem'
    ]);
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(TodoActions.addItem, 'addItem');
            this.listenTo(TodoActions.deleteItem, 'deleteItem');
        },
        addItem: function (model) {
           console.log(model)
        },
        deleteItem:function(model){
            console.log(model);
        }
    });
    
    TodoActions.addItem({name:'xxx'});
    TodoActions.deleteItem({name:'yyy'});
    
    非同期アクション
    実際のアプリケーションシーンでは、ほぼすべての操作がバックエンドに要求されますが、これらの操作は非同期であり、Refluxも対応するPromiseインターフェースを提供しています.
    var getAll = Reflux.createAction({asyncResult:true});
    
    例えば、すべてのデータを取得します.
    var getAll = Reflux.createAction({asyncResult: true});
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(getAll, 'getAll');
        },
        getAll: function (model) {
            $.get('/all', function (data) {
                if (data) {
                    getAll.completed(data);
                } else {
                    getAll.failed(data);
                }
    
            });
        }
    });
    
    getAll({name: 'xxx'})
        .then(function (data) {
            console.log(data);
        })
        .catch(function (err) {
            throw err;
        });
    
    アクションスクール
    Refluxは各actionに対して二つのhook方法を提供しています.
  • preemit(params)、action emitの前に呼び出します.パラメータはactionで渡され、戻り値はshuldEmit
  • に伝えられます.
  • shoruldEmit(params)action emitの前に呼び出し、パラメータはデフォルトでaction転送であり、premitの戻り値があればpreemitの戻り値であり、戻り値はemit
  • かどうかを決定する.
    情景1:
    var addItem = Reflux.createAction({
        preEmit: function (params) {
            console.log('preEmit:' + params);           
        },
        shouldEmit: function (params) {
            console.log('shouldEmit:' + params);           
        }
    });
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (params) {
            console.log('addItem:' + params);
        }
    });
    
    addItem('xxx');
    
         
    $ preEmit:xxx
    $ shouldEmit:xxx
    
    情景二:
    var addItem = Reflux.createAction({
        preEmit: function (params) {
            console.log('preEmit:' + params);
            return 324;
        },
        shouldEmit: function (params) {
            console.log('shouldEmit:' + params);
            return true;
        }
    });
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (params) {
            console.log('addItem:' + params);
        }
    });
    
    addItem('xxx');
    
         
    $ preEmit:xxx
    $ shouldEmit:324
    $ addItem:324
    
    いくつかの戻り値とパラメータの関係に注意してください.
    アクションMethods
    すべてのactionに共通の方法を追加する必要がある場合、このようにしても良いです.
    Reflux.ActionMethods.print = function (str) {
        console.log(str);
    };
    
    var addItem = Reflux.createAction();
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (params) {
            console.log('addItem:' + params);
        }
    });
    
    addItem.print('xxx');
    
    trigger、trigger Asyncとtrigger Promise
    直接addItemを呼び出す()とは、triggerまたはtrigger Asyncまたはtrigger Promiseの違いです.
    var addItem = Reflux.createAction(); addItem();                 #    triggerAsync,   addItem.triggerAsync()
    var addItem = Reflux.createAction({sync:true});addItem();       #    trigger,   addItem.trigger()
    var addItem = Reflux.createAction({asyncResult:true});addItem();#    triggerPromise,   addItem.triggerPromise()
    
    triggerとtrigger Asyncの違いは:
    triggerAsync = setTimeout(function () {
        trigger()
    }, 0);
    
    triggerとtrigger Promiseの違いは、trigger Promiseの戻り値がpromiseであることです.
    Storeを作成
    Storeは、アクションの挙動に応答して、サーバと対話することができる.
    単一のアクションをモニターする
    initメソッドに傍受処理を追加する
    var addItem = Reflux.createAction();
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (model) {
            console.log(model);
        }
    });
    
    addItem({name: 'xxx'});
    
    複数のアクションを傍受する
    融通のきかない書き方
    var TodoActions = Reflux.createActions([
        'addItem',
        'deleteItem'
    ]);
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(TodoActions.addItem, 'addItem');
            this.listenTo(TodoActions.deleteItem, 'deleteItem');
        },
        addItem: function (model) {
            console.log(model);
        },
        deleteItem: function (model) {
            console.log(model);
        }
    });
    
    TodoActions.addItem({name: 'xxx'});
    TodoActions.deleteItem({name: 'yyy'});
    
    二つのactionの時にinitに二回の傍受処理方法を書きましたが、十個以上あったら、このように書きます.
    var TodoActions = Reflux.createActions([
        'item1',
        'item2',
        'item3',
        'item4',
        'item5',
        'item6',
        'item7',
        'item8',
        'item9',
        'item10'
    ]);
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(TodoActions.item1, 'item1');
            this.listenTo(TodoActions.item2, 'item2');
            this.listenTo(TodoActions.item3, 'item3');
            this.listenTo(TodoActions.item4, 'item4');
            this.listenTo(TodoActions.item5, 'item5');
            this.listenTo(TodoActions.item6, 'item6');
            this.listenTo(TodoActions.item7, 'item7');
            this.listenTo(TodoActions.item8, 'item8');
            this.listenTo(TodoActions.item9, 'item9');
            this.listenTo(TodoActions.item10, 'item10');
    
        },
        item1: function (model) {
            console.log(model);
        },
        item2: function (model) {
            console.log(model);
        }
    });
    
    TodoActions.item1({name: 'xxx'});
    TodoActions.item2({name: 'yyy'});
    
    リトントニー
    幸いにもRefluxは私達にlistentoMany方法を提供してくれました.重複労働を避けるために:
    var TodoActions = Reflux.createActions([
        'item1',
        'item2',
        'item3',
        'item4',
        'item5',
        'item6',
        'item7',
        'item8',
        'item9',
        'item10'
    ]);
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenToMany(TodoActions);
        },
        onItem1: function (model) {
            console.log(model);
        },
        onItem2: function (model) {
            console.log(model);
        }
    });
    
    TodoActions.item1({name: 'xxx'});
    TodoActions.item2({name: 'yyy'});
    
    処理方法は、actionのロゴの頭文字を大文字にしてオンを付けるだけでいいです.
    マークは頭文字が大文字であると認識できなくなります.例えば上のitem 1をItme 1に変更します.このおやじさん
    listenables
    var TodoActions = Reflux.createActions([
        'item1',
        'item2',
        'item3',
        'item4',
        'item5',
        'item6',
        'item7',
        'item8',
        'item9',
        'item10'
    ]);
    
    var TodoStore = Reflux.createStore({
        listenables: [TodoActions],
        onItem1: function (model) {
            console.log(model);
        },
        onItem2: function (model) {
            console.log(model);
        }
    });
    
    TodoActions.item1({name: 'xxx'});
    TodoActions.item2({name: 'yyy'});
    
    私たちが実際のアプリケーションを書くときは、このような書き方をするべきです!!!
    Store Methods
    Storeを拡張するための共用方法は2つあります.
    方式1
    Reflux.StoreMethods.print = function (str) {
        console.log(str);
    };
    
    var addItem = Reflux.createAction();
    
    var TodoStore = Reflux.createStore({
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (model) {
            console.log(model);
        }
    });
    
    TodoStore.print('rrr');
    
    方式二
    var Mixins = {
        print: function (str) {
            console.log(str);
        }
    }
    
    var addItem = Reflux.createAction();
    
    var TodoStore = Reflux.createStore({
        mixins: [Mixins],
        init: function () {
            this.listenTo(addItem, 'addItem');
        },
        addItem: function (model) {
            console.log(model);
        }
    });
    
    TodoStore.print('rrr');
    
    コンポーネントと結合する
    前述したように、アクション、Store、コンポーネントの3つは、イベントメカニズムによって応答が変化し、コンポーネントを構築する際には、まずStoreの状態をモニターする必要があります.アクションとStoreを先に定義します.
    var TodoActions = Reflux.createActions([
        'getAll'
    ]);
    
    var TodoStore = Reflux.createStore({
        items: [1,2,3],
        listenables: [TodoActions],
        onGetAll: function () {
            this.trigger(this.items);
        }
    });
    
    基本
    var TodoComponent = React.createClass({
        getInitialState: function () {
            return {list: []};
        },
        onStatusChange: function (list) {
            this.setState({list: list});
        },
        componentDidMount: function () {
            this.unsubscribe = TodoStore.listen(this.onStatusChange);
            TodoActions.getAll();
        },
        componentWillUnmount: function () {
            this.unsubscribe();
        },
        render: function () {
            return (
                
    {this.state.list.map(function (item) { return

    {item}

    })}
    ) } }); React.render(, document.getElementById('container'));
    ここには2つの注意点があります.
  • コンポーネントのライフサイクルが終了すると、Storeのリスニングを解除する必要があります.
  • Storeがtriggerを呼び出すとオンスチャー関数が実行されますので、Store更新のたびに手動でtrigger関数
  • を呼び出す必要があります.
    ミxins
    var TodoComponent = React.createClass({
        mixins: [Reflux.ListenerMixin],
        getInitialState: function () {
            return {list: []};
        },
        onStatusChange: function (list) {
            this.setState({list: list});
        },
        componentDidMount: function () {
            this.unsubscribe = TodoStore.listen(this.onStatusChange);
            TodoActions.getAll();
        },
        render: function () {
            return (
                
    {this.state.list.map(function (item) { return

    {item}

    })}
    ) } }); React.render(, document.getElementById('container'));
    Reflux.listenTo
    var TodoComponent = React.createClass({
        mixins: [Reflux.listenTo(TodoStore,'onStatusChange')],
        getInitialState: function () {
            return {list: []};
        },
        onStatusChange: function (list) {
            this.setState({list: list});
        },
        componentDidMount: function () {
            TodoActions.getAll();
        },
        render: function () {
            return (
                
    {this.state.list.map(function (item) { return

    {item}

    })}
    ) } }); React.render(, document.getElementById('container'));
    Reflux.co nnect
    var TodoComponent = React.createClass({
        mixins: [Reflux.connect(TodoStore,'list')],
        getInitialState: function () {
            return {list: []};
        },
        componentDidMount: function () {
            TodoActions.getAll();
        },
        render: function () {
            return (
                
    {this.state.list.map(function (item) { return

    {item}

    })}
    ) } }); React.render(, document.getElementById('container'));
    データは自動的にstateのリストに更新されます.
    Reflux.co nnect Filter
    var TodoComponent = React.createClass({
        mixins: [Reflux.connectFilter(TodoStore, 'list', function (list) {
            return list.filter(function (item) {
                return item > 1;
            });
        })],
        getInitialState: function () {
            return {list: []};
        },
        componentDidMount: function () {
            TodoActions.getAll();
        },
        render: function () {
            return (
                
    {this.state.list.map(function (item) { return

    {item}

    })}
    ) } }); React.render(, document.getElementById('container'));
    データにフィルタを追加しました.
    以上のComponentとStoreが交互になっている内容は、実際の状況によって異なる書き方を選ぶことができます.
    結び目
    私はコードで思想を表現するのが好きです.
    var TodoActions = Reflux.createActions([
        'getAll',
        'addItem',
        'deleteItem',
        'updateItem'
    ]);
    
    var TodoStore = Reflux.createStore({
        items: [1, 2, 3],
        listenables: [TodoActions],
        onGetAll: function () {
            $.get('/all', function (data) {
                this.items = data;
                this.trigger(this.items);
            }.bind(this));
        },
        onAddItem: function (model) {
            $.post('/add', model, function (data) {
                this.items.unshift(data);
                this.trigger(this.items);
            }.bind(this));
        },
        onDeleteItem: function (model, index) {
            $.post('/delete', model, function (data) {
                this.items.splice(index, 1);
                this.trigger(this.items);
            }.bind(this));
        },
        onUpdateItem: function (model, index) {
            $.post('/update', model, function (data) {
                this.items[index] = data;
                this.trigger(this.items);
            }.bind(this));
        }
    });
    
    
    var TodoComponent = React.createClass({
        mixins: [Reflux.connect(TodoStore, 'list')],
        getInitialState: function () {
            return {list: []};
        },
        componentDidMount: function () {
            TodoActions.getAll();
        },   
        render: function () {
            return (
                
    {this.state.list.map(function(item){ return })}
    ) } }); var TodoItem = React.createClass({ componentDidMount: function () { TodoActions.getAll(); }, handleAdd: function (model) { TodoActions.addItem(model); }, handleDelete: function (model,index) { TodoActions.deleteItem(model,index); }, handleUpdate: function (model) { TodoActions.updateItem(model); }, render: function () { var item=this.props.data; return (

    {item.name}

    {item.email}

    /* */

    ) } }); React.render(, document.getElementById('container'));
    実際の状況はこれよりずっと複雑です.ただ一つの考えを提供して、参考にしてください.
    コードリンク
    github
    参照
    Reflux