当前位置: 首页 > news >正文

bootstrap公司网站百度品牌

bootstrap公司网站,百度品牌,个人网站的建设与管理,做网站的图片要求大小Sebastian Seitz , Mark Brown和Vildan Softic同行评议了使用ngrx / store在Angular 2 Apps中管理状态。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态! 我们为Web应用程序构建的组件通常包含状态。 连接组件可能导致共享可变状态&#…

Sebastian Seitz , Mark Brown和Vildan Softic同行评议了使用ngrx / store在Angular 2 Apps中管理状态。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!

两位科学家打开拿着薛定inger猫的盒子

我们为Web应用程序构建的组件通常包含状态。 连接组件可能导致共享可变状态:这很难管理并且导致不一致。 如果我们有一个地方可以改变状态并让消息完成其余的工作,该怎么办? ngrx / store是使用RxJS的Redux for Angular的实现,它将强大的模式引入了Angular世界。

在本文中,我将介绍共享可变状态的问题,并展示如何使用ngrx / store库解决此问题,并将单向数据流体系结构引入Angular 2应用程序。 在此过程中,我们将构建一个示例应用程序 ,允许用户使用YouTube API搜索视频。

注意:您可以在此GitHub存储库中找到本文随附的代码。

并发问题

建立相互通信的组件是涉及状态的典型任务。 我们经常必须与具有相同状态的不同Angular组件保持最新联系:当多个组件访问并修改该状态时,我们称其为共享可变状态

要了解共享可变状态为何代表问题,请考虑由两个不同用户使用的计算机。 有一天,第一个用户将操作系统更新为最新版本。 一天后,第二个用户打开了计算机,并且由于用户界面没有明显的变化而感到困惑。 发生这种情况是因为两个用户可以在不互相交谈的情况下修改同一个对象(在本例中为计算机)。

实践中的共享可变状态

共享状态的一个常见示例是我们正在执行的操作的属性集。 如果我们正在执行数据库搜索,则将该功能集称为当前搜索 。 从现在开始,我将把这样的集合称为search对象

想象一个页面,它使您可以按名称搜索某些内容,还可以按地理位置限制搜索。 该页面将至少具有两个可以修改当前搜索属性的不同组件。 最有可能的是,将有一个服务负责执行实际搜索。

规则是:

  • 如果名称字段为空,请清除搜索结果
  • 如果仅定义了名称,则按名称执行搜索
  • 如果同时定义了名称和位置,请按名称和位置执行搜索
  • 为了按位置搜索,必须同时提供坐标(纬度/经度)和半径

可用方法

解决共享可变状态问题的一种方法可能是在组件和服务之间来回转发搜索对象,并允许每个对象都对其进行修改。

这将导致更加冗长和复杂的测试,这非常耗时且容易出错:对于每个测试,您都需要模拟对象,仅更改某些属性以仅测试特定行为。 所有这些测试和模拟也都需要维护。

每个组件访问状态

同样,与状态交互的每个组件都需要托管逻辑来做到这一点。 这损害了组件的可重用性,并且违反了DRY原则 。

一种替代方法是将搜索对象封装到服务中,并公开一个基本API来修改搜索值。 但是,该服务将负责三项不同的工作:

  • 执行搜索
  • 保持状态一致
  • 应用参数规则

与单一责任原则相距甚远,该服务现在已成为应用程序本身,不能轻易重用。

即使将该服务拆分为较小的服务,仍然会导致我们拥有不同的服务或组件来修改相同数据的情况。

一项服务负责一切

此外,组件正在消耗服务,因此没有服务就无法使用它们。

一种不同且经常使用的模式是将所有逻辑放入应用程序层,但是最终我们仍然要花费大量代码来保证状态的一致性。

我的意见是,应用程序层(这是真正的独特特征)应仅应用规则。 基础架构可以处理其他任务,即消息传递,存储和事件。

Redux方法

此方法基于Facebook近年来开发的Flux应用程序架构模型以及Elm Architecture 。

AngularJS开发人员也可以在多种实现中使用此模式。 在本教程中,我们将使用ngrx / store,因为它是ngrx包的一部分,该包是Reactive Extensions的正式Angular 2包装器。 此外,它使用Observables实现Redux模式,从而与Angular 2架构保持一致。

它是如何工作的?

  1. 组件发出动作
  2. 操作被调度到状态存储
  3. 减速器功能基于这些动作得出新状态
  4. 通知订户新状态

因此,我们可以分担责任,因为Ngrx / store负责状态一致性,而RxJS带来了消息总线。

一项服务负责一切

  • 我们的组件不会知道服务或应用程序逻辑:它们只是发出操作。
  • 我们的服务没有状态:它只是基于来自外部的搜索对象执行搜索。
  • 我们的应用程序组件仅侦听状态更改并决定要做什么。
  • 新条目减速器实际上将对动作做出反应,并在必要时修改状态。
  • 突变的一个切入点。

示例:YouTube搜索组件

我们将编写一个小型应用程序,以使用YouTube API搜索视频。 您可以在下面看到运行的最终演示 :

克隆入门仓库

克隆存储库的此处开始版本。 在app/文件夹中,我们将找到要使用的实际应用程序文件:

project
├── app
│   ├── app.module.ts
│   ├── app.component.ts
│   └── main.ts
├── index.html
├── LICENSE
├── package.json
├── README.md
├── systemjs.config.js
├── tsconfig.json
└── typings.json

现在,在app文件夹下,我们创建了两个名为models and components文件夹。 我们需要定义的第一件事是要使用的模型。

定义模型

鉴于需要搜索查询,我们需要决定如何表示它。 这将允许按名称位置进行搜索。

/** app/models/search-query.model.ts **/
export interface CurrentSearch {name: string;location?: {latitude: number,longitude: number},radius: number
}

由于位置将是一个选项,因此将其定义为搜索对象的可选属性。

还需要搜索结果的表示形式。 这将包括视频的ID标题缩略图,因为这将在用户界面中显示。

/** app/models/search-result.model.ts*/
export interface SearchResult {id: string;title: string;thumbnailUrl: string;
}

搜索框组件

第一个搜索参数是“按名称”,因此必须创建一个组件,该组件将:

  • 显示文字输入
  • 每次修改文本时调度一个动作

让我们使用组件的定义在app/components下创建一个新文件:

/** app/components/search-box.component.ts **/
@Component({selector: 'search-box',template: `<input type="text" class="form-control" placeholder="Search" autofocus>`
})

该组件还需要对动作进行去抖半秒钟,以避免在快速键入时触发多个动作:

export class SearchBox implements OnInit {static StoreEvents = {text: 'SearchBox:TEXT_CHANGED'};@Input()store: Store<any>;constructor(private el: ElementRef) {}ngOnInit(): void {Observable.fromEvent(this.el.nativeElement, 'keyup').map((e: any) => e.target.value).debounceTime(500).subscribe((text: string) =>this.store.dispatch({type: SearchBox.StoreEvents.text,payload: {text: text}}));}}

可以将其分解如下:为了从DOM事件中获取Observable ,可以使用辅助函数Observable.fromEvent(HTMLNode, string)将键入转换为字符串流,然后使用RxJS工具包对其进行处理。

注意将store定义为输入。 它代表我们的调度员来交付行动。 该组件将不了解消费者,搜索过程或服务。 它只是处理输入字符串并分派它。

请注意调度程序的使用方式:其签名为dispatch(action: Action): void其中Action是具有强制type字段(字符串)和可选payload 。 由于操作的类型是string ,所以我更喜欢将它们定义为组件内具有适当名称空间的常量,以便该操作的任何使用者都可以导入并与其匹配。

邻近选择器组件

提供的第二种搜索控制是“按地理位置”,从而提供了纬度和经度坐标。 因此,我们需要一个组件,它将:

  • 显示一个复选框以打开本地化
  • 每次修改本地化时调度一个动作
  • 显示半径的范围输入
  • 每次半径改变时都派一个动作

逻辑仍然相同:显示输入,触发动作。

/** app/components/proximity-selector.component.ts **/
@Component({selector: 'proximity-selector',template: `<div class="input-group"><label for="useLocation">Use current location</label><input type="checkbox"[disabled]="disabled"(change)="onLocation($event)"></div><div class="input-group"><label for="locationRadius">Radius</label><input type="range" min="1" max="100" value="50"[disabled]="!active"(change)="onRadius($event)"></div>`
})

它与前面的搜索框组件非常相似。 但是,模板是不同的,因为现在必须显示两个不同的输入。 此外,如果位置关闭,我们希望禁用半径。

这是实现:

/** app/components/proximity-selector.component.ts **/
export class ProximitySelector {static StoreEvents = {position: 'ProximitySelector:POSITION',radius: 'ProximitySelector:RADIUS',off: 'ProximitySelector:OFF'};@Input()store: Store<any>;active = false;// put here the event handlers}

现在,这两个事件处理程序需要实现。 首先,将处理该复选框:

/** app/components/proximity-selector.component.ts **/
export class ProximitySelector {// ...onLocation($event: any) {this.active = $event.target.checked;if (this.active) {navigator.geolocation.getCurrentPosition((position: any) => {this.store.dispatch({type: ProximitySelector.StoreEvents.position,payload: {position: {latitude: position.coords.latitude,longitude: position.coords.longitude}}});});} else {this.store.dispatch({type: ProximitySelector.StoreEvents.off,payload: {}});}}
}

第一步是检测本地化是打开还是关闭:

  • 如果开启,将分派当前职位
  • 如果关闭,将发送相应的消息

这次使用回调,因为数据不像数字流,而是单个事件。

最后,添加了半径的处理程序,无论位置如何,都将分派新值,因为我们有disabled属性为我们工作。

/** app/components/proximity-selector.component.ts **/
export class ProximitySelector {// ...onRadius($event: any) {const radius = parseInt($event.target.value, 10);this.store.dispatch({type: ProximitySelector.StoreEvents.radius,payload: {radius: radius}});}
}

减速器

这与调度程序一起是新系统的核心。 减速器是一种功能,该功能处理动作和当前状态以产生新状态。

归约器的一个重要特性是它们是可组合的,允许我们在保持状态原子的同时将逻辑拆分为不同的函数。 因此,它们必须是纯函数 :换句话说,它们没有副作用。

这给我们带来了另一个重要的推论:测试纯函数是微不足道的,因为给定相同的输入将产生相同的输出。

我们需要的化简器将处理组件中定义的动作,为应用程序返回新状态。 以下是图形说明:

该图显示了SearchReducer如何采用CurrentSearch状态和一个操作来产生新状态

减速器应在app/reducers/下的新文件中创建:

/** app/components/search.reducer.ts **/
export const SearchReducer: ActionReducer<CurrentSearch> = (state: CurrentSearch, action: Action) => {switch (action.type) {// put here the next case statements// first define the default behaviordefault:return state;}
};

我们必须处理的第一个动作是非动作:如果该动作不影响状态,则reducer会将其返回未经修改的状态。 这对于避免破坏模型非常重要。

接下来,我们处理文本更改操作:

/** app/components/search.reducer.ts **/switch (action.type) {case SearchBox.StoreEvents.text:return Object.assign({}, state, {name: action.payload.text});// ...}

如果该动作是SearchBox组件公开的动作,则我们知道有效负载包含新文本。 因此,我们只需要修改state对象的text字段。

根据最佳做法 ,我们不会改变状态,而是创建一个新状态并将其返回。

最后,处理与本地化有关的动作:

  • 对于ProximitySelector.StoreEvents.position我们需要更新位置值
  • 对于ProximitySelector.StoreEvents.radius我们只需要更新半径值
  • 如果消息是ProximitySelector.StoreEvents.off我们只需将位置和半径都设置为null
/** app/components/search.reducer.ts **/switch (action.type) {case ProximitySelector.StoreEvents.position:return Object.assign({}, state, {location: {latitude: action.payload.position.latitude,longitude: action.payload.position.longitude}});case ProximitySelector.StoreEvents.radius:return Object.assign({}, state, {radius: action.payload.radius});case ProximitySelector.StoreEvents.off:return Object.assign({}, state, {location: null});// ...}

一起布线

至此,我们有两个分派动作的组件和一个处理消息的reducer。 下一步是连接所有元素并进行测试。

首先,让我们将新组件导入应用程序模块app/app.module.ts

/** app/app.module.ts **/
import {ProximitySelector} from "./components/proximity-selector.component";
import {SearchBox} from "./components/search-box.component";
import {SearchReducer} from "./reducers/search.reducer";// the rest of app component

接下来,我们修改模块的元数据以将SearchBoxProximitySelector为指令:

/** app/app.module.ts **/
@NgModule({// ... other dependenciesdeclarations: [ AppComponent, SearchBox, ProximitySelector ],// ...
})

然后,我们需要提供一个商店,该商店将负责调度动作,并针对状态和动作运行化简器。 可以使用StoreModule模块的provideStore函数来创建。 我们传递一个带有商店名称和处理它的化简器的对象。

/** app/app.module.ts **/
// before the @Component definition
const storeManager = provideStore({ currentSearch: SearchReducer });

现在,我们将商店经理放入提供商列表中:

/** app/app.module.ts **/
@NgModule({imports:      [ BrowserModule, HttpModule, StoreModule, storeManager ],// ...
})

最后,但非常重要的是,我们需要将组件放置在模板中,并将它们作为输入传递给store

/** app/app.component.ts **/
@Component({// ...same as beforetemplate: `<h1>{{title}}</h1><div class="row"><search-box [store]="store"></search-box><proximity-selector [store]="store"></proximity-selector></div><p>{{ state | json }}</p>`
})

该类需要更新以符合新模板:

/** app/app.component.ts **/
export class AppComponent implements OnInit {private state: CurrentSearch;private currentSearch: Observable<CurrentSearch>;constructor(private store: Store<CurrentSearch>) {this.currentSearch = this.store.select<CurrentSearch>('currentSearch');}ngOnInit() {this.currentSearch.subscribe((state: CurrentSearch) => {this.state = state;});}
}

在这里,我们定义了一个私有属性,该属性表示要公开的状态(对于UI)。 存储服务被注入到我们的构造函数中,并用于获取currentSearch的实例。 OnInit接口用于获取init阶段的挂钩,从而允许组件使用商店的实例订阅状态的更新。

下一步是什么?

现在,可以实现一个简单的服务,该服务接受CurrentSearch并像实时示例中一样调用后端API(例如,可以是YouTube )。 可以更改服务,而无需更改一行组件或应用程序的实现。

此外, ngrx不仅限于商店: effectsselectors等几种工具可用于处理更复杂的情况,例如处理异步HTTP请求。

结论

在本教程中,我们看到了如何使用ngrx / store和RxJs在Angular 2中实现类似Redux的流程。

最重要的是,由于突变是许多问题的根源,因此将其放在一个受控制的位置将有助于我们编写更具可维护性的代码。 我们的组件与逻辑分离,应用程序不知道其行为的详细信息。

值得一提的是,我们使用的模式与ngrx官方文档中显示的模式不同,因为这些组件是直接分派操作的,而没有使用事件和其他智能组件层。 关于最佳实践的讨论仍在不断发展。

您是否尝试过ngrx,还是更喜欢Redux? 我很想听听您的想法!

From: https://www.sitepoint.com/managing-state-angular-2-ngrx/

http://www.lbrq.cn/news/2800243.html

相关文章:

  • 三亚建设局网站河南seo技术教程
  • 怎么让自己做的网站让别人看到百度指数是怎么计算的
  • 头像网站模板baidu百度首页官网
  • 160;作者:网站建设&自己建站的网站
  • 专业做网站的人网络营销推广渠道有哪些
  • 导航网站 黄色托管竞价账户哪家好
  • 可视化网站开发系统介绍电子商务网络营销
  • 购物网站 后台近10天的时政新闻
  • 做外贸需要浏览外国网站商品促销活动策划方案
  • 湖南益阳网站建设网络营销主要有哪些特点
  • 购物网站模板 php如何进行搜索引擎优化?
  • 动漫设计需要学什么关键词优化排名要多少钱
  • 建设工程合同的内容北京专门做seo
  • 公司软件网站建设重庆网站推广
  • 自己买主机可以做网站吗seo是什么牌子
  • 上海做网站价格上海百度研发中心
  • html网站开发实验报告全网热度指数
  • 青岛免费网站建站模板最新热搜新闻事件
  • 企业网站seo营销最新域名8xgmvxyz
  • 做企业网站代码那种好google优化排名
  • bootstrap 案例网站宁波seo专员
  • 辽阳网站推广磁力狗在线
  • ip网站怎么做个人网页免费域名注册入口
  • 做集团网站的亚马逊查关键词搜索量的工具
  • 做网站泰州广州seo服务外包
  • 做网站的接口是意思自己怎么开发app软件
  • 答题助手网站怎么做的品牌推广活动策划案例
  • 海尔建设网站的目的电商网站搭建
  • 做正品的网站杭州百度开户
  • 做菠菜网站代理国外网站seo
  • MiniGPT-4
  • 【Java集合】List,Map,Set-详细讲解
  • Git常用操作大全(附git操作命令)
  • 带有 Angular V14 的 Highcharts
  • (第二十五节课内容总结)
  • CISP-PTE之路--10文