成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Immutable & Redux in Angular Way

lunaticf / 857人閱讀

摘要:來(lái)源于社區(qū),時(shí)至今日已經(jīng)基本成為的標(biāo)配了。部分很簡(jiǎn)單,要根據(jù)傳入的執(zhí)行不同的操作。當(dāng)性能遇到瓶頸時(shí)基本不會(huì)遇到,可以更改,保證傳入數(shù)據(jù)來(lái)提升性能。當(dāng)不再能滿足程序開(kāi)發(fā)的要求時(shí),可以嘗試使用進(jìn)行函數(shù)式編程。

Immutable & Redux in Angular Way 寫(xiě)在前面

AngularJS 1.x版本作為上一代MVVM的框架取得了巨大的成功,現(xiàn)在一提到Angular,哪怕是已經(jīng)和1.x版本完全不兼容的Angular 2.x(目前最新的版本號(hào)為4.2.2),大家還是把其作為典型的MVVM框架,MVVM的優(yōu)點(diǎn)Angular自然有,MVVM的缺點(diǎn)也變成了Angular的缺點(diǎn)一直被人詬病。

其實(shí),從Angular 2開(kāi)始,Angular的數(shù)據(jù)流動(dòng)完全可以由開(kāi)發(fā)者自由控制,因此無(wú)論是快速便捷的雙向綁定,還是現(xiàn)在風(fēng)頭正盛的Redux,在Angular框架中其實(shí)都可以得到很好的支持。

Mutable

我們以最簡(jiǎn)單的計(jì)數(shù)器應(yīng)用舉例,在這個(gè)例子中,counter的數(shù)值可以由按鈕進(jìn)行加減控制。

counter.component.ts代碼

import { Component, ChangeDetectionStrategy, Input } from "@angular/core";

@Component({
  selector       : "app-counter",
  templateUrl    : "./counter.component.html",
  styleUrls      : []
})
export class CounterComponent {
  @Input()
  counter = {
    payload: 1
  };
  
  increment() {
    this.counter.payload++;
  }

  decrement() {
    this.counter.payload--;
  }

  reset() {
    this.counter.payload = 1;
  }

}

counter.component.html代碼

Counter: {{ counter.payload }}

現(xiàn)在我們?cè)黾右幌滦枨?,要求counter的初始值可以被修改,并且將修改后的counter值傳出。在Angular中,數(shù)據(jù)的流入和流出分別由@Input和@Output來(lái)控制,我們分別定義counter component的輸入和輸出,將counter.component.ts修改為

import { Component, Input, Output, EventEmitter } from "@angular/core";
@Component({
  selector   : "app-counter",
  templateUrl: "./counter.component.html",
  styleUrls  : []
})
export class CounterComponent {
  @Input() counter = {
    payload: 1
  };
  @Output() onCounterChange = new EventEmitter();

  increment() {
    this.counter.payload++;
    this.onCounterChange.emit(this.counter);
  }

  decrement() {
    this.counter.payload--;
    this.onCounterChange.emit(this.counter);
  }

  reset() {
    this.counter.payload = 1;
    this.onCounterChange.emit(this.counter);
  }
}

當(dāng)其他component需要使用counter時(shí),app.component.html代碼

app.component.ts代碼

import { Component } from "@angular/core";
@Component({
  selector   : "app-root",
  templateUrl: "./app.component.html",
  styleUrls  : [ "./app.component.less" ]
})
export class AppComponent {
  initCounter = {
    payload: 1000
  }

  onCounterChange(counter) {
    console.log(counter);
  }
}

在這種情況下counter數(shù)據(jù)

會(huì)被當(dāng)前counter component中的函數(shù)修改

也可能被initCounter修改

如果涉及到服務(wù)端數(shù)據(jù),counter也可以被Service修改

在復(fù)雜的應(yīng)用中,還可能在父component通過(guò)@ViewChild等方式獲取后被修改

框架本身對(duì)此并沒(méi)有進(jìn)行限制,如果開(kāi)發(fā)者對(duì)數(shù)據(jù)的修改沒(méi)有進(jìn)行合理的規(guī)劃時(shí),很容易導(dǎo)致數(shù)據(jù)的變更難以被追蹤。

與AngularJs 1.x版本中在特定函數(shù)執(zhí)行時(shí)進(jìn)行臟值檢查不同,Angular 2+使用了zone.js對(duì)所有的常用操作進(jìn)行了monkey patch,有了zone.js的存在,Angular不再像之前一樣需要使用特定的封裝函數(shù)才能對(duì)數(shù)據(jù)的修改進(jìn)行感知,例如ng-click或者$timeout等,只需要正常使用(click)或者setTimeout就可以了。

與此同時(shí),數(shù)據(jù)在任意的地方可以被修改給使用者帶來(lái)了便利的同時(shí)也帶來(lái)了性能的降低,由于無(wú)法預(yù)判臟值產(chǎn)生的時(shí)機(jī),Angular需要在每個(gè)瀏覽器事件后去檢查更新template中綁定數(shù)值的變化,雖然Angular做了大量的優(yōu)化來(lái)保證性能,并且成果顯著(目前主流前端框架的跑分對(duì)比),但是Angular也提供了另一種開(kāi)發(fā)方式。

Immutable & ChangeDetection

在Angular開(kāi)發(fā)中,可以通過(guò)將component的changeDetection定義為ChangeDetectionStrategy.OnPush從而改變Angular的臟值檢查策略,在使用OnPush模式時(shí),Angular從時(shí)刻進(jìn)行臟值檢查的狀態(tài)改變?yōu)閮H在兩種情況下進(jìn)行臟值檢查,分別是

當(dāng)前component的@Input輸入值發(fā)生更換

當(dāng)前component或子component產(chǎn)生事件

反過(guò)來(lái)說(shuō)就是當(dāng)@Input對(duì)象mutate時(shí),Angular將不再進(jìn)行自動(dòng)臟值檢測(cè),這個(gè)時(shí)候需要保證@Input的數(shù)據(jù)為Immutable

將counter.component.ts修改為

import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from "@angular/core";
@Component({
  selector       : "app-counter",
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl    : "./counter.component.html",
  styleUrls      : []
})
export class CounterComponent {
  @Input() counter = {
    payload: 1
  };
  @Output() onCounterChange = new EventEmitter();

  increment() {
    this.counter.payload++;
    this.onCounterChange.emit(this.counter);
  }

  decrement() {
    this.counter.payload--;
    this.onCounterChange.emit(this.counter);
  }

  reset() {
    this.counter.payload = 1;
    this.onCounterChange.emit(this.counter);
  }
}

將app.component.ts修改為

import { Component } from "@angular/core";
@Component({
  selector   : "app-root",
  templateUrl: "./app.component.html",
  styleUrls  : [ "./app.component.less" ]
})
export class AppComponent {
  initCounter = {
    payload: 1000
  }

  onCounterChange(counter) {
    console.log(counter);
  }

  changeData() {
    this.initCounter.payload = 1;
  }
}

將app.component.html修改為


這個(gè)時(shí)候點(diǎn)擊change發(fā)現(xiàn)counter的值不會(huì)發(fā)生變化。

將app.component.ts中changeData修改為

changeData() {
  this.initCounter = {
    ...this.initCounter,
    payload: 1
  }
}

counter值的變化一切正常,以上的代碼使用了Typescript 2.1開(kāi)始支持的 Object Spread,和以下代碼是等價(jià)的

changeData() {
  this.initCounter = Object.assign({}, this.initCounter, { payload: 1 });
}

在ChangeDetectionStrategy.OnPush時(shí),可以通過(guò)ChangeDetectorRef.markForCheck()進(jìn)行臟值檢查,官網(wǎng)范點(diǎn)擊此處,手動(dòng)markForCheck可以減少Angular進(jìn)行臟值檢查的次數(shù),但是不僅繁瑣,而且也不能解決數(shù)據(jù)變更難以被追蹤的問(wèn)題。

通過(guò)保證@Input的輸入Immutable可以提升Angular的性能,但是counter數(shù)據(jù)在counter component中并不是Immutable,數(shù)據(jù)的修改同樣難以被追蹤,下一節(jié)我們來(lái)介紹使用Redux思想來(lái)構(gòu)建Angular應(yīng)用。

Redux & Ngrx Way

Redux來(lái)源于React社區(qū),時(shí)至今日已經(jīng)基本成為React的標(biāo)配了。Angular社區(qū)實(shí)現(xiàn)Redux思想最流行的第三方庫(kù)是ngrx,借用官方的話來(lái)說(shuō)RxJS powered,inspired by Redux,靠譜。

如果你對(duì)RxJS有進(jìn)一步了解的興趣,請(qǐng)?jiān)L問(wèn)https://rxjs-cn.github.io/rxj...

基本概念

和Redux一樣,ngrx也有著相同View、Action、Middleware、Dispatcher、Store、Reducer、State的概念。使用ngrx構(gòu)建Angular應(yīng)用需要舍棄Angular官方提供的@Input和@Output的數(shù)據(jù)雙向流動(dòng)的概念。改用Component->Action->Reducer->Store->Component的單向數(shù)據(jù)流動(dòng)。

以下部分代碼來(lái)源于CounterNgrx和這篇文章

我們使用ngrx構(gòu)建同樣的counter應(yīng)用,與之前不同的是這次需要依賴@ngrx/core@ngrx/store

Component

app.module.ts代碼,將counterReducer通過(guò)StoreModule import

import {BrowserModule} from "@angular/platform-browser";
import {NgModule} from "@angular/core";
import {FormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";

import {AppComponent} from "./app.component";
import {StoreModule} from "@ngrx/store";
import {counterReducer} from "./stores/counter/counter.reducer";

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    StoreModule.provideStore(counterReducer),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}

在NgModule中使用ngrx提供的StoreModule將我們的counterReducer傳入

app.component.html

Counter: {{ counter | async }}

注意多出來(lái)的async的pipe,async管道將自動(dòng)subscribe Observable或Promise的最新數(shù)據(jù),當(dāng)Component銷毀時(shí),async管道會(huì)自動(dòng)unsubscribe。

app.component.ts

import {Component} from "@angular/core";
import {CounterState} from "./stores/counter/counter.store";
import {Observable} from "rxjs/observable";
import {Store} from "@ngrx/store";
import {DECREMENT, INCREMENT, RESET} from "./stores/counter/counter.action";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  counter: Observable;

  constructor(private store: Store) {
    this.counter = store.select("counter");
  }

  increment() {
    this.store.dispatch({
      type: INCREMENT,
      payload: {
        value: 1
      }
    });
  }

  decrement() {
    this.store.dispatch({
      type: DECREMENT,
      payload: {
        value: 1
      }
    });
  }

  reset() {
    this.store.dispatch({type: RESET});
  }
}

在Component中可以通過(guò)依賴注入ngrx的Store,通過(guò)Store select獲取到的counter是一個(gè)Observable的對(duì)象,自然可以通過(guò)async pipe顯示在template中。

dispatch方法傳入的內(nèi)容包括typepayload兩部分, reducer會(huì)根據(jù)typepayload生成不同的state,注意這里的store其實(shí)也是個(gè)Observable對(duì)象,如果你熟悉Subject,你可以暫時(shí)按照Subject的概念來(lái)理解它,store也有一個(gè)next方法,和dispatch的作用完全相同。

Action

counter.action.ts

export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
export const RESET     = "RESET";

Action部分很簡(jiǎn)單,reducer要根據(jù)dispath傳入的action執(zhí)行不同的操作。

Reducer

counter.reducer.ts

import {CounterState, INITIAL_COUNTER_STATE} from "./counter.store";
import {DECREMENT, INCREMENT, RESET} from "./counter.action";
import {Action} from "@ngrx/store";

export function counterReducer(state: CounterState = INITIAL_COUNTER_STATE, action: Action): CounterState {
  const {type, payload} = action;

  switch (type) {
    case INCREMENT:
      return {...state, counter: state.counter + payload.value};

    case DECREMENT:
      return {...state, counter: state.counter - payload.value};

    case RESET:
      return INITIAL_COUNTER_STATE;

    default:
      return state;
  }
}

Reducer函數(shù)接收兩個(gè)參數(shù),分別是state和action,根據(jù)Redux的思想,reducer必須為純函數(shù)(Pure Function),注意這里再次用到了上文提到的Object Spread。

Store

counter.store.ts

export interface CounterState {
  counter: number;
}

export const INITIAL_COUNTER_STATE: CounterState = {
  counter: 0
};

Store部分其實(shí)也很簡(jiǎn)單,定義了couter的Interface和初始化state。

以上就完成了Component->Action->Reducer->Store->Component的單向數(shù)據(jù)流動(dòng),當(dāng)counter發(fā)生變更的時(shí)候,component會(huì)根據(jù)counter數(shù)值的變化自動(dòng)變更。

總結(jié)

同樣一個(gè)計(jì)數(shù)器應(yīng)用,Angular其實(shí)提供了不同的開(kāi)發(fā)模式

Angular默認(rèn)的數(shù)據(jù)流和臟值檢查方式其實(shí)適用于絕大部分的開(kāi)發(fā)場(chǎng)景。

當(dāng)性能遇到瓶頸時(shí)(基本不會(huì)遇到),可以更改ChangeDetection,保證傳入數(shù)據(jù)Immutable來(lái)提升性能。

當(dāng)MVVM不再能滿足程序開(kāi)發(fā)的要求時(shí),可以嘗試使用Ngrx進(jìn)行函數(shù)式編程。

這篇文章總結(jié)了很多Ngrx優(yōu)缺點(diǎn),其中我覺(jué)得比較Ngrx顯著的優(yōu)點(diǎn)是

數(shù)據(jù)層不僅相對(duì)于component獨(dú)立,也相對(duì)于框架獨(dú)立,便于移植到其他框架

數(shù)據(jù)單向流動(dòng),便于追蹤

Ngrx的缺點(diǎn)也很明顯

實(shí)現(xiàn)同樣功能,代碼量更大,對(duì)于簡(jiǎn)單程序而言使用Immutable過(guò)度設(shè)計(jì),降低開(kāi)發(fā)效率

FP思維和OOP思維不同,開(kāi)發(fā)難度更高

參考資料

Immutability vs Encapsulation in Angular Applications

whats-the-difference-between-markforcheck-and-detectchanges

Angular 也走 Redux 風(fēng) (使用 Ngrx)

Building a Redux application with Angular 2

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83692.html

相關(guān)文章

  • 2017-09-23 前端日?qǐng)?bào)

    摘要:知乎專欄前端給不了解前端的同學(xué)講前端掘金前端夠得到安全跨站請(qǐng)求偽造掘金前端面試問(wèn)題持續(xù)更新掘金向核心貢獻(xiàn)代碼的六個(gè)步驟基于的仿音樂(lè)移動(dòng)端個(gè)人文章用構(gòu)建組件網(wǎng)易嚴(yán)選感受開(kāi)發(fā)已完結(jié)掘金英文 2017-09-23 前端日?qǐng)?bào) 精選 [譯] 網(wǎng)絡(luò)現(xiàn)狀:性能提升指南前端夠得到Web安全3--點(diǎn)擊劫持/UI-覆蓋攻擊React, Jest, Flow, Immutable.js將改用MIT開(kāi)源協(xié)議N...

    BingqiChen 評(píng)論0 收藏0
  • (譯 & 轉(zhuǎn)載) 2016 JavaScript 后起之秀

    摘要:在年成為最大贏家,贏得了實(shí)現(xiàn)的風(fēng)暴之戰(zhàn)。和他的競(jìng)爭(zhēng)者位列第二沒(méi)有前端開(kāi)發(fā)者可以忽視和它的生態(tài)系統(tǒng)。他的殺手級(jí)特性是探測(cè)功能,通過(guò)檢查任何用戶的功能,以直觀的方式讓開(kāi)發(fā)人員檢查所有端點(diǎn)。 2016 JavaScript 后起之秀 本文轉(zhuǎn)載自:眾成翻譯譯者:zxhycxq鏈接:http://www.zcfy.cc/article/2410原文:https://risingstars2016...

    darry 評(píng)論0 收藏0
  • 關(guān)于前端數(shù)據(jù)&邏輯的思考

    摘要:這里引出了一個(gè)概念,就是數(shù)據(jù)流這個(gè)概念,在項(xiàng)目中我將所有數(shù)據(jù)的操作都成為數(shù)據(jù)的流動(dòng)。 最近重構(gòu)了一個(gè)項(xiàng)目,一個(gè)基于redux模型的react-native項(xiàng)目,目標(biāo)是在混亂的代碼中梳理出一個(gè)清晰的結(jié)構(gòu)來(lái),為了實(shí)現(xiàn)這個(gè)目標(biāo),首先需要對(duì)項(xiàng)目的結(jié)構(gòu)做分層處理,將各個(gè)邏輯分離出來(lái),這里我是基于典型的MVC模型,那么為了將現(xiàn)有代碼重構(gòu)為理想的模型,我需要做以下幾步: 拆分組件 邏輯處理 抽象、...

    alin 評(píng)論0 收藏0
  • 2017-06-23 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選大前端公共知識(shí)梳理這些知識(shí)你都掌握了嗎以及在項(xiàng)目中的實(shí)踐深入貫徹閉包思想,全面理解閉包形成過(guò)程重溫核心概念和基本用法前端學(xué)習(xí)筆記自定義元素教程阮一峰的網(wǎng)絡(luò)日志中文譯回調(diào)是什么鬼掘金譯年,一個(gè)開(kāi)發(fā)者的好習(xí)慣知乎專 2017-06-23 前端日?qǐng)?bào) 精選 大前端公共知識(shí)梳理:這些知識(shí)你都掌握了嗎?Immutable.js 以及在 react+redux 項(xiàng)目中的實(shí)踐深入貫徹閉包思...

    Vixb 評(píng)論0 收藏0
  • React-redux進(jìn)階之Immutable.js

    摘要:的優(yōu)勢(shì)保證不可變每次通過(guò)操作的對(duì)象都會(huì)返回一個(gè)新的對(duì)象豐富的性能好通過(guò)字典樹(shù)對(duì)數(shù)據(jù)結(jié)構(gòu)的共享的問(wèn)題與原生交互不友好通過(guò)生成的對(duì)象在操作上與原生不同,如訪問(wèn)屬性,。 Immutable.js Immutable的優(yōu)勢(shì) 1. 保證不可變(每次通過(guò)Immutable.js操作的對(duì)象都會(huì)返回一個(gè)新的對(duì)象) 2. 豐富的API 3. 性能好 (通過(guò)字典樹(shù)對(duì)數(shù)據(jù)結(jié)構(gòu)的共享) Immutab...

    孫淑建 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<