React Reflux

观点

Reflux是依据React的flux建立的单向数据流类库。
Reflux的单向数据流形式主要由actions和stores构成。比方,当组件list新增item时,会挪用actions的某个要领(如addItem(data)),并将新的数据当参数通报进去,经由历程事宜机制,数据会通报到stroes中,stores能够向服务器提议要求,并更新数据数据库。数据更新胜利后,照样经由历程事宜机制通报的组件list当中,并更新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 (
            <div>
                {this.state.list.map(function (item) {
                    return <p>{item}</p>
                })}
            </div>
        )
    }
});


React.render(<TodoComponent />, document.getElementById('container'));

同React Flux比较

相同点

  • 有actions
  • 有stores
  • 单向数据流

差别点

  • 经由历程内部拓展actions的行动,移除了单例的dispatcher
  • stores能够监听actions的行动,无需举行芜杂的switch推断
  • stores能够互相监听,能够举行进一步的数据聚合操纵,类似于,map/reduce
  • waitFor被一连和平行的数据流所替换

建立Action

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'});

建立多个Action

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'});

异步Action

实在的运用场景中,险些一切的操纵都邑向后端要求,而这些操纵都是异步的,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;
    });

Action hooks

Reflux为每一个action都供应了两个hook要领

  • preEmit(params),action emit之前挪用,参数是action通报过来的,返回值会通报给shouldEmit
  • shouldEmit(params) action emit之前挪用,参数默许是action通报,假如preEmit有返回值,则是preEmit返回值,返回值决议是不是emit

情形一:

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

注重几个返回值和参数的关联

Action 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、triggerAsync和triggerPromise

直接挪用addItem()实际上是挪用trigger或许triggerAsync或许triggerPromise,它们区分在于

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和triggerAsync区分在于:

triggerAsync = setTimeout(function () {
    trigger()
}, 0);

trigger和triggerPromise区分在于,triggerPromise的返回值是promise

建立Store

Store能够相应Action的行动,并同服务器交互。

监听单个Action

在init要领中增加监听处置惩罚

var addItem = Reflux.createAction();

var TodoStore = Reflux.createStore({
    init: function () {
        this.listenTo(addItem, 'addItem');
    },
    addItem: function (model) {
        console.log(model);
    }
});

addItem({name: 'xxx'});

监听多个Action

作死写法

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'});

listenToMany

还好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的标识首字母大写并加上on就能够了。

标识假如首字母大写就会辨认不了,比方将上面的item1改成Itme1。这坑爹的!

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的公用要领有两种体式格局。

体式格局一

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');

同组件连系

前面说了,Action、Store和组件这三者是经由历程事宜机制相应变化的,构建组件的时刻起首须要监听Store的状况。
先定义Action和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 (
            <div>
                {this.state.list.map(function (item) {
                    return <p>{item}</p>
                })}
            </div>
        )
    }
});    
React.render(<TodoComponent />, document.getElementById('container'));

这里有两点须要注重:

  • 当组件的生命周期结束时须要消除对Store的监听
  • 当Store挪用trigger时,才会实行onStatusChange函数,所以每次Store更新时,须要手动挪用trigger函数

Mixins

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 (
            <div>
                {this.state.list.map(function (item) {
                    return <p>{item}</p>
                })}
            </div>
        )
    }
});
React.render(<TodoComponent />, 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 (
            <div>
                {this.state.list.map(function (item) {
                    return <p>{item}</p>
                })}
            </div>
        )
    }
});
React.render(<TodoComponent />, document.getElementById('container'));

Reflux.connect

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

数据会自动更新到state的list当中。

Reflux.connectFilter

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 (
            <div>
                {this.state.list.map(function (item) {
                    return <p>{item}</p>
                })}
            </div>
        )
    }
});
React.render(<TodoComponent />, 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 (
            <div>
                {this.state.list.map(function(item){
                    return <TodoItem data={item}/>
                })}
            </div>
        )
    }
});

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 (
            <div>
                <p>{item.name}</p>
                <p>{item.email}</p>
                <p>/*操纵按钮*/</p>
            </div>
        )
    }
});
React.render(<TodoComponent />, document.getElementById('container'));

实际情况远比这庞杂,只是供应一个思绪供人人参考。

代码链接

github

参考

Reflux

    原文作者:小俞
    原文地址: https://segmentfault.com/a/1190000002793786
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞