22、探索Flux架构中的视图组件与库应用

Flux架构中视图与库的选择

探索Flux架构中的视图组件与库应用

1. Flux架构中视图组件的另类选择

一般而言,Flux架构应尽可能减少存储(store)的数量。但当在视图层使用Handlebars时,可能会影响存储的设计。例如,为减少DOM结构重新插入文档,可能会对应用的整体状态进行拆分。

1.1 事件处理

在现代Web框架出现之前,jQuery就致力于解决跨浏览器的事件处理问题。尽管其API多年来有所变化,但强大的事件处理能力始终未变。在使用jQuery和Handlebars构建视图时,这一能力尤为重要。

事件处理的主要挑战在于,每次Handlebars模板更新时都要重新渲染元素。我们不希望每次将DOM元素插入DOM时都重新附加事件处理程序。ReactJS采用的策略是不直接将事件处理程序绑定到要监听的元素上,而是绑定到body元素,当事件冒泡时调用相应的处理程序。这种方法具有性能优势,避免了反复将相同的处理函数绑定到同一元素上。

以下是使用jQuery实现类似效果的示例。首先来看Handlebars模板文件,以了解所处理的UI类型。增加了一个反转按钮和选择功能,新的项目视图模板如下:

<a href="#{{@index}}" style="font-weight: {{fontWeight}}">
  <span style="text-transform: capitalize">{{first}}</span>
  <span style="text-transform: capitalize">{{last}}</span>
</a>

项目现在是一个链接,可使用 @index Handlebars语法访问当前项在集合中的索引。主列表视图Handlebars模板如下:

<button>Reverse</button>
<ul>
  {{#each users}}
  <li>{{> item-view}}</li>
  {{/each}}
</ul>

现在有一个新按钮用于反转列表的排序顺序。视图组件的事件处理能力代码如下:

import template from './list-view.hbs';
import { reverse } from '../actions/reverse';
import { select } from '../actions/select';
import myStore from '../stores/my-store';

export default class ListView {
  constructor(element) {
    this.element = element;
    myStore.on('change', (state) => {
      this.render(state);
    });
    this.element
      .on('click', 'button', reverse)
      .on('click', 'a', (e) => {
        e.preventDefault();
        let index = +(/(\d+)$/).exec(e.currentTarget.href)[1];
        select(index);
      });
  }
  render(state = myStore.state) {
    this.element.html(template(state));
    return this;
  }
}

这里遵循了React的模式,事件处理程序不会直接附加到频繁重新渲染的元素上。第一个处理程序用于反转按钮,使用 reverse() 动作创建函数;第二个处理程序在用户点击链接时调用,阻止默认浏览器行为并调度选择事件。

为支持新的事件行为,对存储进行了一些更改。存储的初始状态如下:

var state = {
  users: [
    {
      first: 'first 1',
      last: 'last 1',
      fontWeight: 'normal'
    },
    {
      first: 'first 2',
      last: 'last 2',
      fontWeight: 'normal'
    },
    {
      first: 'first 3',
      last: 'last 3',
      fontWeight: 'normal'
    }
  ]
};

存储类 MyStore 的代码如下:

import { EventEmitter } from 'events';
import dispatcher from '../dispatcher';
import { REVERSE } from '../actions/reverse';
import { SELECT } from '../actions/select';

class MyStore extends EventEmitter {
  constructor() {
    super();
    this.id = dispatcher.register((e) => {
      switch(e.type) {
        case REVERSE:
          this.emit('change', (state = Object.assign({}, state, { users: state.users.reverse() })));
          break;
        case SELECT:
          this.emit('change', (state = Object.assign({}, state, { users: state.users.map((v, i) => {
            if (i === e.payload) {
              return Object.assign({}, v, { fontWeight: 'bold' });
            } else {
              return Object.assign({}, v, { fontWeight: 'normal' });
            }
          })})));
          break;
      }
    });
  }
  get state() {
    return state;
  }
}

export default new MyStore();

主要有两个重要更改:一是用户数组中的每个项都新增了 fontWeight 属性,用于控制链接的显示以指示选择状态;二是增加了SELECT处理逻辑,根据有效负载索引匹配项并更改字体粗细。

1.2 使用VanillaJS

前端JavaScript渲染库生态系统的多样性并非问题,相反,可供选择的库和框架过多。在某些阶段,过早选择视图库可能会限制技术的使用,而等待太久再做决定,将基于纯JS构建的视图迁移到更具倾向性的方法会变得困难。

最佳策略是尽可能避免技术锁定,保持组件的松散耦合,使其可替换。Flux架构使这一目标易于实现,因为视图层的职责相对有限,只需监听存储的更改事件并渲染存储状态。可以尝试构建两套视图组件,一套使用React等技术,另一套使用jQuery和Handlebars等其他技术,这样既能选择最适合产品的视图技术,又能测试采用新技术的准备情况。

1.3 转向React

在Flux架构的视图组件中,可以使用jQuery和Handlebars等技术,且它们不会干扰Flux架构中的单向数据流。然而,React可能是最适合作为Flux架构一部分的视图技术。从单向数据流的角度来看,React能自然地实现这一点。即使没有Flux,无状态的功能性React组件的行为也符合Flux架构中视图的预期,即新属性传入时渲染新的HTML。

此外,由于React使用虚拟DOM来修补渲染输出,而不是替换整个内容,重新渲染大型DOM结构不再那么令人畏惧。React还能处理一些边缘情况,如在重新渲染期间保持表单控件的焦点。

虽然转向React的可能性很大,但也存在一些负面权衡,如更高的内存消耗。不过,由于视图在Flux架构中作用相对较小,如果转向React能解决视图组件中的问题,那么这是一个不错的方向。

1.4 新技术的涌现

几年前,React还是新兴技术。开发者应对新技术保持一定的怀疑态度,并非所有新的闪亮技术都能成功。例如,Google正在实现名为Incremental DOM的视图技术,它采用不同的渲染方法,内存消耗更低,还有Veu.js等。要确保视图能够适应并采用最新、最优秀的视图技术。

2. 利用Flux库

Flux本质上是一套架构指南,虽提供了极大的灵活性,但在决定如何实现特定的Flux组件时可能会让人不知所措。幸运的是,有一些优秀的Flux库提供了有倾向性的Flux组件实现,减少了大量样板代码的编写。

2.1 实现核心Flux组件

可以改变Flux架构中各种组件的实现细节,下面分别讨论调度器、存储和动作及动作创建函数。

组件 说明
调度器 可对其进行定制。Facebook的参考实现虽可用,但并非每个生产环境的Flux架构都必须使用。可以将调度器模块中的 dispatch() register() 函数暴露出来,使调度器的使用更直接。通用的Flux库甚至可能完全取消调度器,但仍能实现其架构原则。
存储 之前对存储层次结构进行了改进,让每个存储继承自一个基类,自动完成存储在调度器上的注册。方法动作处理程序原本是调度器的功能,现在或许基类存储是实现此功能的合适位置。如果发现多个存储有通用的状态转换行为,基类存储便于提取公共代码。
动作和动作创建函数 在Flux架构中,常量是明确表示动作的好方法。动作模块定义常量,动作创建函数将常量传递给调度器,存储在处理动作时也使用这些常量。之前采用了不同的方法,允许存储定义方法处理程序,但这降低了常量的价值。Flux库可以简化动作的调度和处理,减少处理常量时的人为错误。此外,对于异步动作创建函数,其异步行为通常遵循类似的模式,Flux库可将其生命周期抽象为通用函数。
2.2 实现痛点

在实现Flux架构时,存在一些痛点。异步动作难以正确实现,将应用状态划分到存储中是一个棘手的设计问题,若处理不当,很难挽回。此外,还需考虑数据依赖的挑战。

综上所述,在Flux架构的实践中,无论是视图组件的选择还是Flux库的利用,都需要综合考虑各种因素,以构建出高效、灵活的应用架构。

探索Flux架构中的视图组件与库应用

3. 不同Flux库的实现差异

为了展示不同的Flux实现方式,下面将以两个Flux库为例进行说明。虽然目标不是追求完全合规,但要构建一个能帮助应用完成任务的坚实架构。

3.1 调度器的定制差异

不同的Flux库对调度器的实现有不同的方式。有的库可能会像之前提到的那样,将 dispatch() register() 函数暴露出来,让使用更直接;而有些库可能会完全隐藏调度器的实现细节,只提供一个简单的接口供开发者使用。以下是一个简单的对比表格:

库特点 调度器暴露情况 实现复杂度 灵活性
库A 暴露 dispatch() register() 适中 较高
库B 隐藏调度器细节,提供简单接口 较低 相对较低

从这个表格可以看出,不同库在调度器的实现上各有优劣。如果开发者需要更高的灵活性,可能会选择像库A这样的实现;而如果希望快速开发,减少复杂度,库B可能更合适。

3.2 存储的处理差异

存储在不同Flux库中的处理方式也有所不同。有些库可能会提供一个强大的基类存储,包含各种通用的状态转换方法,开发者可以直接继承使用;而另一些库可能只提供最基本的存储功能,让开发者自己去实现具体的逻辑。

以下是一个mermaid格式的流程图,展示了不同库中存储的处理流程差异:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B{选择库}:::decision
    B -->|库C| C(继承强大基类存储):::process
    B -->|库D| D(实现基本存储功能):::process
    C --> E(使用通用状态转换方法):::process
    D --> F(自定义状态转换逻辑):::process
    E --> G([结束]):::startend
    F --> G

从这个流程图可以清晰地看到,不同库在存储处理上的路径不同。选择哪种库取决于开发者对存储功能的需求和开发的便捷性。

3.3 动作处理的差异

动作处理在不同Flux库中也存在差异。有些库可能会强调使用常量和 switch 语句来明确动作的处理,而有些库可能会采用更灵活的方式,如使用方法处理程序。以下是一个列表说明:
- 库E
- 强调使用常量和 switch 语句,动作处理逻辑清晰,易于理解和维护。
- 示例代码:

switch(action.type) {
    case 'ACTION_TYPE_1':
        // 处理逻辑
        break;
    case 'ACTION_TYPE_2':
        // 处理逻辑
        break;
}
  • 库F
    • 采用方法处理程序,让存储直接定义与动作匹配的方法。
    • 示例代码:
class MyStore {
    handleActionType1() {
        // 处理逻辑
    }
    handleActionType2() {
        // 处理逻辑
    }
}

不同的动作处理方式各有优缺点,开发者可以根据项目的需求和团队的开发习惯来选择。

4. 总结与建议

在Flux架构的实践中,视图组件的选择和Flux库的利用都至关重要。以下是一些总结和建议:

4.1 视图组件选择
  • 对于初期项目,可先使用jQuery和Handlebars等熟悉的技术构建视图组件,快速实现功能。
  • 随着项目的发展,如果对性能和单向数据流有更高要求,可考虑转向React。
  • 保持多种视图组件的实现,以便在需要时进行切换和测试。
4.2 Flux库使用
  • 根据项目的复杂度和团队的开发能力选择合适的Flux库。
  • 关注库在调度器、存储和动作处理等方面的实现差异,选择最符合需求的库。
  • 注意异步动作处理、状态划分和数据依赖等实现痛点,选择能有效解决这些问题的库。

总之,Flux架构提供了很大的灵活性,开发者需要根据具体情况做出合适的选择,以构建出高效、灵活且易于维护的应用架构。同时,要保持对新技术的关注,以便在合适的时候引入更好的解决方案。

基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内容概要:本文围绕“基于数据驱动的Koopman算子的递归神经网络模型线性化”展开,旨在研究纳米定位系统的预测控制问题,并提供完整的Matlab代码实现。文章结合数据驱动方法Koopman算子理论,利用递归神经网络(RNN)对非线性系统进行建模线性化处理,从而提升纳米级定位系统的精度动态响应性能。该方法通过提取系统隐含动态特征,构建近似线性模型,便于后续模型预测控制(MPC)的设计优化,适用于高精度自动化控制场景。文中还展示了相关实验验证仿真结果,证明了该方法的有效性和先进性。; 适合人群:具备一定控制理论基础和Matlab编程能力,从事精密控制、智能制造、自动化或相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于纳米级精密定位系统(如原子力显微镜、半导体制造设备)中的高性能控制设计;②为非线性系统建模线性化提供一种结合深度学习现代控制理论的新思路;③帮助读者掌握Koopman算子、RNN建模模型预测控制的综合应用。; 阅读建议:建议读者结合提供的Matlab代码逐段理解算法实现流程,重点关注数据预处理、RNN结构设计、Koopman观测矩阵构建及MPC控制器集成等关键环节,并可通过更换实际系统数据进行迁移验证,深化对方法泛化能力的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值