現(xiàn)代前端框架的重要概念

許多初學(xué)者經(jīng)常會(huì)問(wèn) “我需要學(xué)習(xí)哪個(gè)框架 株婴?” 以及 “學(xué)習(xí)框架前需要掌握多少 JS 或者 TS ?” 無(wú)數(shù)帶有主觀色彩的文章都在宣傳作者首選框架或庫(kù)的優(yōu)勢(shì),而不是向讀者展示其背后的概念以做出更明智的決定。所以讓我們先解決第二個(gè)問(wèn)題

學(xué)習(xí)框架前需要掌握多少 JS 或者 TS

盡可能多地去學(xué)以讓更好的你理解它們所基于的概念旺坠。你將需要了解基本數(shù)據(jù)類(lèi)型、函數(shù)扮超、基本運(yùn)算符和文檔對(duì)象模型 ( DOM )取刃,這是 HTML 和 CSS 在 JS 中的表示。除此之外的一切也都 OK出刷,但并不嚴(yán)格要求某個(gè)精通框架或庫(kù)璧疗。

如果你是一個(gè)完完全全的新手,JS for cats?應(yīng)該是一個(gè)不錯(cuò)的入門(mén)資料馁龟。持續(xù)學(xué)習(xí)崩侠,直到你感到自信為止,然后繼續(xù)前進(jìn)坷檩,直到你再次感到自信為止却音。當(dāng)掌握了足夠的 JS / TS 知識(shí)后改抡,你就可以開(kāi)始學(xué)習(xí)框架。其他的知識(shí)你可以并行學(xué)習(xí)僧家。

哪些重要概念

State (狀態(tài))

Effects (副作用)

Memoization (記憶化)

Templating and rendering (模板與渲染)

所有現(xiàn)代框架都從這些概念中派生出它們的功能

state

State 只是為你的應(yīng)用程序提供動(dòng)力的數(shù)據(jù)雀摘。它可能在全局級(jí)別,適用于應(yīng)用程序的大部分組件八拱,或適用于單個(gè)組件。讓我們寫(xiě)一個(gè)計(jì)數(shù)器的簡(jiǎn)單例子來(lái)說(shuō)明一下涯塔。它保留的計(jì)數(shù)是 state 肌稻。我們可以讀取 state 或者寫(xiě)入 state 以增加計(jì)數(shù)

最簡(jiǎn)單的表示通常是一個(gè)變量,其中包含我們的狀態(tài)所包含的數(shù)據(jù):

letcount =0;constincrement= () => { count++; };constbutton =document.createElement('button'); button.textContent= count; button.addEventListener('click', increment);document.body.appendChild(button);

但這個(gè)代碼有個(gè)問(wèn)題:類(lèi)似調(diào)用?increment?方法一樣去修改?count?的值 爹耗,并不會(huì)自動(dòng)修改 button 的文案苔悦。我們需要手動(dòng)去更新所有的內(nèi)容奏寨,但這樣的做法在復(fù)雜場(chǎng)景下代碼的可維護(hù)性 & 擴(kuò)展性都不是很好。

讓?count?自動(dòng)更新依賴(lài)它的使用方的能力稱(chēng)之為?reactivity(響應(yīng)式)?诺凡。這是通過(guò)訂閱并重新運(yùn)行應(yīng)用程序的訂閱部分來(lái)更新的。

幾乎所有的現(xiàn)代前端框架和庫(kù)都擁有讓 state 變成 reactivity 的能力践惑「姑冢基本上可以分為 3 種解決方案,采用其中至少一種或者多種混用來(lái)實(shí)現(xiàn)這個(gè)能力:

Observables / Signals (可觀察的 / 信號(hào))

Reconciliation of immutable updates (協(xié)調(diào)不可變的更新)

Transpilation (轉(zhuǎn)譯)

這些概念還是直接用英文表達(dá)比較貼切 ??

Observables / Signals (可觀察的 / 信號(hào))

Observables 基本上是在讀取 state 的時(shí)候通過(guò)一個(gè)訂閱方法來(lái)收集依賴(lài)尔觉,然后在更新的時(shí)候觸發(fā)依賴(lài)的更新

conststate= (initialValue) => ({_value: initialValue,get:function() {/* 訂閱 */;returnthis._value;? },set:function(value) {this._value= value;/* 觸發(fā)更新 */;? }});

knockout?是最早使用這個(gè)概念的框架之一凉袱,它使用帶有 / 不帶參數(shù)的相同函數(shù)進(jìn)行寫(xiě)/讀訪問(wèn)

這種模式最近有開(kāi)始有框架通過(guò) signals 來(lái)實(shí)現(xiàn),比如?Solid.js?和preact signals?侦铜;相同的模式也在?Vue?和Svelte?中使用到专甩。RxJS 為 Angular 的 reactive 層提供底層能力,是這一模式的延伸钉稍,超越了簡(jiǎn)單狀態(tài)涤躲。Solid.js?用 Stores(一些通過(guò) setter 方法來(lái)操作的對(duì)象)的方式進(jìn)一步抽象了 signals

Reconciliation of immutable states(協(xié)調(diào)不可變的更新)

不可變意味著如果對(duì)象的某個(gè)屬性發(fā)生改變,那么整個(gè)對(duì)象的引用就會(huì)發(fā)生改變贡未。所以協(xié)調(diào)器做的事情就包括通過(guò)簡(jiǎn)單的引用對(duì)比就判斷出對(duì)象是否發(fā)生了改變

conststate1 = {todos: [{text:'understand immutability',complete:false}],currentText:''};// 更新 currentText 屬性conststate2 = {todos: state1.todos,currentText:'understand reconciliation'};// 添加一個(gè) todoconststate3 = {todos: [? ? state1.todos[0],? ? {text:'understand reconciliation',complete:true}? ],currentText:''};// 由于不可變性种樱,這里將會(huì)報(bào)錯(cuò)state3.currentText='I am not immutable!';

如你所見(jiàn),未變更項(xiàng)目的引用被重新使用羞秤。如果協(xié)調(diào)器檢測(cè)到不同的對(duì)象引用缸托,那么它將重新運(yùn)行所有的組件,讓所有的組件的 state (props, memos, effects, context) 都使用最新的這個(gè)對(duì)象瘾蛋。由于讀取訪問(wèn)是被動(dòng)的俐镐,所以需要手動(dòng)指定對(duì)響應(yīng)值的依賴(lài)。

很顯然哺哼,你不會(huì)用上面這種方式定義 state 佩抹。要么你是從一個(gè)已經(jīng)存在的屬性構(gòu)造 state 叼风,要么你會(huì)使用?reducer?來(lái)構(gòu)造 state。一個(gè) reducer 函數(shù)就是接收一個(gè) state 對(duì)象然后返回一個(gè)新的 state 對(duì)象棍苹。

reactpreact?就使用這種模式无宿。它適合與 vDOM 一起使用,我們將在稍后描述模板時(shí)探討它枢里。

并不是所有的框架都借助 vDOM 將 state 變成完成響應(yīng)式孽鸡。例如?Mithril.JS?要不是在 state 修改后觸發(fā)對(duì)應(yīng)的生命周期事件,要不是手動(dòng)調(diào)用?m.redraw()?方法栏豺,才能夠觸發(fā)更新

Transpilation(轉(zhuǎn)譯)

Transpilation 是在構(gòu)建階段彬碱,重寫(xiě)我們的代碼讓代碼可以在舊的瀏覽器運(yùn)行或者賦予代碼其他的能力;在這種情況下奥洼,轉(zhuǎn)譯則是被用于把一個(gè)簡(jiǎn)單的變量修改成響應(yīng)式系統(tǒng)的一部分巷疼。

Svelte?就是基于轉(zhuǎn)譯器,該轉(zhuǎn)譯器還通過(guò)看似簡(jiǎn)單的變量聲明和訪問(wèn)為他們的響應(yīng)式系統(tǒng)提供能力

另外灵奖,Solid.js?也是使用 Transpilation 嚼沿,但 Transpilation 只使用到模版上,沒(méi)有使用到 state 上

Effects

大部分情況下瓷患,我們需要做的更多是操作響應(yīng)式的 state骡尽,而很少需要操作基于 state 的 DOM 渲染。我們需要管理好副作用尉尾,這些副作用是由于視圖更新之外的狀態(tài)變化而發(fā)生的所有事情(雖然有些框架把視圖更新也當(dāng)作是副作用爆阶,例如

?https://b23.tv/5CVC7NX

https://b23.tv/BY7NBFf

https://b23.tv/0eHr98g

https://b23.tv/qVGZIUB

記得之前 state 的例子中,我們故意把訂閱操作的代碼留空∩秤剑現(xiàn)在讓我們把這些留空補(bǔ)齊來(lái)處理副作用辨图,讓程序能夠響應(yīng)更新

constcontext = [];conststate= (initialValue) => ({_subscribers:newSet(),_value: initialValue,get:function() {constcurrent = context.at(-1);if(current) {this._subscribers.add(current); }returnthis._value;? },set:function(value) {if(this._value=== value) {return; }this._value= value;this._subscribers.forEach(sub=>sub());? }});consteffect= (fn) => {constexecute= () => {? ? context.push(execute);try{fn(); }finally{ context.pop(); }? };execute();};

上面代碼基本上是對(duì)?preact signals或者Solid.js?響應(yīng)式 state 的簡(jiǎn)化版本,它不包含錯(cuò)誤處理和復(fù)雜狀態(tài)處理(使用一個(gè)函數(shù)接收之前的狀態(tài)值肢藐,返回下一個(gè)狀態(tài)值)故河,但這些都是很容易就可以加上的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吆豹,隨后出現(xiàn)的幾起案子鱼的,更是在濱河造成了極大的恐慌,老刑警劉巖痘煤,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凑阶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡衷快,警方通過(guò)查閱死者的電腦和手機(jī)宙橱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人师郑,你說(shuō)我怎么就攤上這事环葵。” “怎么了宝冕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵张遭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我地梨,道長(zhǎng)菊卷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任宝剖,我火速辦了婚禮的烁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诈闺。我一直安慰自己,他們只是感情好铃芦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布雅镊。 她就那樣靜靜地躺著,像睡著了一般刃滓。 火紅的嫁衣襯著肌膚如雪仁烹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天咧虎,我揣著相機(jī)與錄音卓缰,去河邊找鬼。 笑死砰诵,一個(gè)胖子當(dāng)著我的面吹牛征唬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茁彭,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼总寒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了理肺?” 一聲冷哼從身側(cè)響起摄闸,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妹萨,沒(méi)想到半個(gè)月后年枕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乎完,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年熏兄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡霍弹,死狀恐怖毫别,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情典格,我是刑警寧澤岛宦,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站耍缴,受9級(jí)特大地震影響砾肺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜防嗡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一变汪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蚁趁,春花似錦裙盾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至钢属,卻和暖如春徘熔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背淆党。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工酷师, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人染乌。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓山孔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親慕匠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饱须,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 什么是跨域? 跨域是指一個(gè)域下的文檔或腳本試圖去請(qǐng)求另一個(gè)域下的資源台谊,這里跨域是廣義的蓉媳。 廣義的跨域: 1.) 資...
    Jokery閱讀 581評(píng)論 0 0
  • cookie 前言 網(wǎng)絡(luò)早期最大的問(wèn)題之一是如何管理狀態(tài)。簡(jiǎn)而言之锅铅,服務(wù)器無(wú)法知道兩個(gè)請(qǐng)求是否來(lái)自同一個(gè)瀏覽器酪呻。當(dāng)...
    O螞蟻O閱讀 562評(píng)論 0 0
  • 背景 在編碼的過(guò)程中變量命名是一個(gè)容易忽略,又容易犯頭疼的問(wèn)題盐须。例如在復(fù)雜的頁(yè)面布局中 Class 的命名玩荠,同樣一...
    沐深閱讀 1,986評(píng)論 0 2
  • 前端應(yīng)用的 bundle 體積是影響應(yīng)用性能的主要方面之一,我們看下取自 HTTP Archive - Loadi...
    涅槃快樂(lè)是金閱讀 159評(píng)論 0 1
  • WebSocket 出現(xiàn)前 構(gòu)建網(wǎng)絡(luò)應(yīng)用的過(guò)程中,我們經(jīng)常需要與服務(wù)器進(jìn)行持續(xù)的通訊以保持雙方信息的同步阶冈。通常這種...
    NeWolf閱讀 5,492評(píng)論 1 1