【译】Flux入门

栏目: JavaScript · 发布时间: 6年前

内容简介:原文地址:TL;DR 当我在努力学习Flux时,我希望有人告诉我:它并不简单,没有好的详细文档,并且有许多变化的部分。如果你的应用程序需要处理动态数据(dynamic data)的话,那么答案就是yes,你可能需要使用Flux。

原文地址: blog.andrewray.me/flux-for-st… ,作者:Andrew Ray

TL;DR 当我在努力学习Flux时,我希望有人告诉我:它并不简单,没有好的详细文档,并且有许多变化的部分。

我需要使用Flux吗?

如果你的应用程序需要处理动态数据(dynamic data)的话,那么答案就是yes,你可能需要使用Flux。

如果你的应用程序仅仅是无需共享状态静态视图(static view),并且你从不保存也不更新数据,那么你不需要使用Flux,Flux不会给你带来任何好处。

为什么是Flux?

皮一下,因为Flux是个一个适度复杂的主意,为啥增加复杂度呢?

90%的iOS应用程序是表格视图中的数据。iOS工具包具有良好定义的视图和数据模型可以让应用开发变得简单。

但是在前端(Font End:HTML,JS,CSS),我们甚至都没有。相反,我们遇到一个很大的问题:没有人知道应该如何去构建一个前端应用。我从事这个行业多年,从来没人教给我“最佳实践”,相反,他们教了我好多“库(libraries)”,诸如jQuery,Angular,Backbone等等。但是真正的问题、数据流,仍然避开了我们。

什么是Flux?

Flux是一个用来描述具有非常特定事件和监听的“单向”数据流的词。没有官方的Flux库,但是你需要 Flux Dispatcher 和任何的JavaScriptevent library。

官方文档写的就像某人的意识流一样,从这里开始学习是不太好的。但是一旦你掌握了Flux,它可以帮助你填补空白。

不要试图把Flux同MVC架构进行比较,它们的相似之处只会令人困惑。

正式入坑!我将按顺序解释概念,并且一个一个地构建它们。

1.视图的“Dispatch”和“Actions”

Dispatcher(调度员)本质上是一个加入了额外规则的事件系统。它来广播事件并注册回调。全局的dispatcher只有唯一的一个,你应该使用Facebook Dispatcher Library。实例化非常容易:

var AppDispatcher = new Dispatcher();  
复制代码

假设你的应用程序有一个“新建”按钮来向列表添加项目。

<button onClick={ this.createNewItem }>New Item</button>  
复制代码

点击会发生什么?你的视图会调度 一个非常具体的“操作” ,其中包含操作名称和新项目数据:

createNewItem: function( evt ) {

    AppDispatcher.dispatch({
        actionName: 'new-item',
        newItem: { name: 'Marco' } // example data
    });

}
复制代码

action ”是Facebook创造的另一个词。它是一个JavaScript对象,用以描述我们 想要做什么事情 ,以及做这件事我们 需要的数据 。正如你所见到的,我们要做的事情就是添加一个 new-item ,我们需要的数据就是项目 name

2."Store"响应调度的操作

像Flux一样,“Store”这个词也是Facebook创造的.对于我们的应用程序,我们需要列表的特定逻辑和数据集合。这描述了我们的Store,我们称之为ListStore。

Store是一个单体对象,意味着你可能不能通过“new”关键字来声明它,应用程序中每个Store里只有一个实例。

// Single object representing list data and logic
var ListStore = {

    // Actual collection of model data
    items: []

};
复制代码

然后,Store会响应已分派的操作:

var ListStore = …

// Tell the dispatcher we want to listen for *any*
// dispatched events
AppDispatcher.register( function( payload ) {

    switch( payload.actionName ) {

        // Do we know how to handle this action?
        case 'new-item':

            // We get to mutate data!
            ListStore.items.push( payload.newItem );
            break;

    }

}); 
复制代码

这是Flux处理调度回调的传统方式。每个有效负载(payload)包含一个action的名称(actionName)和数据(newItem),switch语句确定Store是否应该响应action,并且知道根据action的类型处理数据变化。

:key:关键点:store 不是数据模型一个Store包含模型

:key:关键点:store在你的应用程序中唯一知道如何更新数据的东西, 它是Flux中最重要的部分 。我们调度的action并不知道如何添加或者删除项目。

举个栗子,假如应用程序中不同的部分需要保持跟踪某些图片及其元数据,那么你就需要创建其他的store,并将其命名为ImageStore。一个 store相当于应用程序中一个单独的“域(domain)” ,如果应用程序非常庞大,这些域可能对你来说已经很明显了。如果应用程序很小,你可能只需要一个store。一般来说,一种模型类型只对应一个Store。

只有store允许注册Dispatcher的回调!view永远不应该调用 AppDispatcher.register 。Dispatcher应该只用于将消息从视图View发送到Store。视图(view)会响应不同类型的事件。

3. Store触发“Change”事件

即将完成!现在数据确实已经变化了,我们需要告诉全世界! Store触发一个事件(Event),但是不会使用dispatcher。这虽然令人困惑,但是这就是Flux的方式。让我们给我们的Store加入触发事件的能力。如果你正在使用MicroEvent.js,那么很简单:

MicroEvent.mixin( ListStore );  
复制代码

然后,触发changes事件

case 'new-item':

            ListStore.items.push( payload.newItem );

            // Tell the world we changed!
            ListStore.trigger( 'change' );

            break;
复制代码

:key:关键点:当我们触发事件的时候,我们不会传递最新的项目。视图View只关心有事情发生变化了。让我们继续关注数据以了解原因。

4. 视图(View)响应“Change”事件

现在我们需要展示列表。当列表发生变化时, 视图会完全地重新渲染(re-render)。

首先,当组件“安装(mount)”时,即组件首次被创建的时候,从ListStore中监听change事件:

componentDidMount: function() {  
    ListStore.bind( 'change', this.listChanged );
},
复制代码

为简单起见,我们只调用forceUpdate,它可以触发重新渲染(re-render)

listChanged: function() {  
    // Since the list changed, trigger a new render.
    this.forceUpdate();
},
复制代码

当组件“卸载(unmount)”的时候,不要忘记清除事件监听器

componentWillUnmount: function() {  
    ListStore.unbind( 'change', this.listChanged );
},
复制代码

现在怎么办?让我们来看看我的render函数,我故意将其保存到最后。

render: function() {

    // Remember, ListStore is global!
    // There's no need to pass it around
    var items = ListStore.getAll();

    // Build list items markup by looping
    // over the entire list
    var itemHtml = items.map( function( listItem ) {

        // "key" is important, should be a unique
        // identifier for each list item
        return <li key={ listItem.id }>
            { listItem.name }
          </li>;

    });

    return <div>
        <ul>
            { itemHtml }
        </ul>

        <button onClick={ this.createNewItem }>New Item</button>

    </div>;
}

复制代码

现在已经完整了。当你添加新项目的时,View 发出用户的 Action,Dispatcher 收到 Action,要求 Store 进行相应的更新,store改变数据,然后store会触发change事件,最后视图通过重新渲染页面来响应change事件。

【译】Flux入门

译者注:原文无此图

但这里有一个问题:每次列表更改时我们都会重新渲染整个视图!这不是非常低效吗?

不。

当然,我们将再次调用render函数,并确保渲染函数中的所有代码都将重新运行。但是,如果渲染输出已更改,React将仅更新真实DOM。您的render函数实际上是生成一个“虚拟DOM”,React与之前的输出进行比较render。如果两个虚拟DOM不同,React将仅使用差异更新真实DOM.

:key:关键点:当Store的数据改变时,视图不应该关心是否有东西被添加,删除,或是被改变了。视图应该只去做重新渲染。React 的“虚拟DOM”差异算法会去处理这些重大问题,找出那些真正发生变化的DOM节点。这会让您的生活更加简单,并降低您的血压。

还有一件事:“Action Creator”到底是个啥?

记住,当我们点击按钮的时候,会分配一个具体的动作(action):

AppDispatcher.dispatch({  
    eventName: 'new-item',
    newItem: { name: 'Samantha' }
});
复制代码

好吧,如果您的许多视图需要发送此操作,则可以重复输入。此外,您的所有视图都需要知道特定的对象格式。那太蹩脚了。Flux建议一种抽象,称为 Action Creator ,它只是将上述内容抽象为一个函数。

ListActions = {

    add: function( item ) {
        AppDispatcher.dispatch({
            eventName: 'new-item',
            newItem: item
        });
    }

};
复制代码

现在您的视图可以调用 ListActions.add({ name: '...' }); ,而不必担心调度的对象语法。

PS:不要使用forceUpdate

我因为习惯了 forceUpdate 这个简单的缘故。组件读取store数据的正确方法,是将数据拷贝到 state ,并且在 render 函数中读取 this.state 。您可以在 TodoMVC example 中看到它的工作原理。

首次加载组件时, store的数据被拷贝到 state ,当store更新时候,数据被完整地重新拷贝。这样做是更好的,因为在内部, forceUpdate 是同步的,同时 setState 的效率也是非常高的。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python科学计算(第2版)

Python科学计算(第2版)

张若愚 / 清华大学出版社 / 2016-4-29 / 118

本书介绍如何用 Python 开发科学计算的应用程序,除了介绍数值计算之外,还着重介绍了如何制作交互式二维、三维图像,如何设计精巧的程序界面,如何与 C 语言编写的高速计算程序结合,如何编写声音、图像处理算法等内容。本书采用 IPython notebook 编写,所有的程序均能在本书提供的运行环境中正常运行,书中所印刷的图表以及程序输出为均为自动运行的结果,保证了书中所有程序的正确性以及可读性。......一起来看看 《Python科学计算(第2版)》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具