摘要:而是假設(shè)我們創(chuàng)建的都是一種名為的首類元素,它應(yīng)當(dāng)可以作為函數(shù)的參數(shù)或返回值進(jìn)行傳遞,而不僅僅只是傳遞其計(jì)算值,即滿足其身為的特性可以被其它引用它的函數(shù)或?qū)ο笥^察到它的變化當(dāng)然,目前中并不存在這樣的首類元素。
原文:what-is-my-state
閱讀前須知
本文獻(xiàn)給對前端狀態(tài)管理 state management 有思考的同學(xué)。
文章有涉及 函數(shù)式編程、響應(yīng)式編程 概念
原文是 slide,所以是言不成章的。本文為了通順,加了一些過渡。還有,由于 slide 常用于演講,所以文字說明不是很多。我補(bǔ)上了一些個(gè)人的理解(以引用塊的樣式),但也不是很多,有時(shí)候會(huì)再出文章解釋一些術(shù)語,如 lens 和 atom 等。
文中的 state 和「狀態(tài)」是同義的,有時(shí)為了強(qiáng)調(diào)和更易于理解,保留了這一術(shù)語未翻譯,讀者請自行腦內(nèi)替換。
本文中的「我」指原作者
口味調(diào)查在我給出我的口味前,下面幾個(gè)矛盾,你會(huì)怎么選擇?
無狀態(tài) vs 狀態(tài)化
程序是基于狀態(tài)的,所以它不可能被完全地清除,但它必須被管理起來。
可變狀態(tài) vs 不可變狀態(tài)
狀態(tài)隨著時(shí)間而變化,所以不可變狀態(tài)這個(gè)說法是自相矛盾的。人們可以在狀態(tài)的一個(gè)點(diǎn)上捕捉到不可變的值,但狀態(tài)本身并不全部不可變。
全局狀態(tài) vs 局部狀態(tài)
來自外部的、共享的、全局狀態(tài)實(shí)際上優(yōu)于被封裝在內(nèi)部的本地狀態(tài)。這也是本篇文章要討論的要點(diǎn)之一。
這篇文章不會(huì)提出新發(fā)明。
Most papers in computer science describe how their author learned what someone else already knew. — Peter Landin
我們的討論基于我在 Calmm 中的實(shí)踐
Calmm 是一個(gè)用于編寫響應(yīng)式 UI 的框架。鼓勵(lì)使用外部共享的狀態(tài),和持續(xù)可觀察的屬性(continuous observable properties)。
在贊美 Calmm 之前,我們需要達(dá)成一些共識(shí)
局部狀態(tài)有毒
為什么不用事件
本文的目標(biāo)希望咱們能從一個(gè)嶄新的角度討論 state ?
State 什么是 statehas value,有值
has identity,有索引
can change over time, 隨著時(shí)間會(huì)變化
狀態(tài)管理難在哪里?值、索引和時(shí)間相互交織,索引和時(shí)間尤其復(fù)雜。
追蹤索引常常導(dǎo)致算法復(fù)雜化,比如 React 中的 key
隨著時(shí)間變化,依賴于狀態(tài)的一些計(jì)算會(huì)無效化
語言層面的局限一般的語言 (比如 js)對 state 這種數(shù)據(jù)基本都不做原生支持。
這體現(xiàn)在,在這些語言中:
變量是可變的、對象上的字段也是可變的
根本上來說,是次類元素
無法組合
無法分形(decompose)
無法(隨著時(shí)間)響應(yīng)變化
什么叫次類元素?這個(gè)說法對應(yīng)于首類元素 first-class,它
無法通過函數(shù)返回
無法作為參數(shù)傳遞
演示局限無法(隨著時(shí)間)響應(yīng)變化
let x = 1 // 創(chuàng)建了一個(gè)可變的 state let y = 2 let sum = x + y // 獲取了 state 的快照 snapshot,值為 3 x = 3 sum // 值還是 3,sum 無法觀察 x 賦值后的值,隨之變化值為 5
state 不是語言中的 first-class 元素
function foo() { let x = 1 // 創(chuàng)建可變的 state bar(x) // 無法將 state 作為參數(shù)傳遞,只能傳遞值,即 1 x = 2 // 修改了 state ,但這對于函數(shù) bar 來說是不可知的 return x // 也無法將 state 作為返回,只能返回值,即 2 }
Make State Fun Again如果你了解 js ,知道變量區(qū)分值類型和引用類型、形參實(shí)參的分別,那么就不會(huì)覺得上面的代碼有任何奇怪的地方。甚至你會(huì)覺得如果 x 重新賦值后, sum 會(huì)隨之變化為 5、對已經(jīng)調(diào)用完畢的 bar 還能產(chǎn)生影響,那才太可怕了。
但其實(shí)上面的代碼,并不是在挑戰(zhàn)這些東西。而是假設(shè)我們創(chuàng)建的 x 都是一種名為 state 的首類元素,它應(yīng)當(dāng)可以
作為函數(shù)的參數(shù)或返回值進(jìn)行傳遞,而不僅僅只是傳遞其計(jì)算值,即滿足其身為 first-class 的特性
可以被其它引用它的函數(shù)或?qū)ο笥^察到它的變化
當(dāng)然,目前 js 中并不存在這樣的首類元素。
neta Make American Great Again, 哈哈
我們試試在 js 中模擬出 State
下文代碼都是 typescript
interface State構(gòu)造首類元素 state{ get(): T; set(value: T): void; }
我們已經(jīng)說過首類元素的特性了,可以作為函數(shù)的參數(shù)和返回值傳遞。
class Atom { constructor(value) { this.value = value } get() { return this.value } set(value) { this.value = value } }
現(xiàn)在在組件中,我們就可以聲明一個(gè) state 來作為參數(shù)了。
Observable stateclass Atom { constructor(value) { this.value = value this.observers = [] } get() { return this.value } set(value) { this.value = value this.observers.forEach(observer => observer(value)) } subscribe(observer) { observer(this.get()) this.observers.push(observer) } }
state 能獨(dú)立于時(shí)間變化了(Independence from time)
可分形的 statedecomposable
class LensedAtom { constructor({getter, setter}, source) { this.getter = getter this.setter = setter this.source = source } get() { return this.getter(this.source.get()) } set(value) { this.source.set(this.setter(value, this.source.get())) } }
把 store state 作為一個(gè)整體,而其分片的元素作為組件的 state
可組合的 stateclass PairAtom { constructor([lhs, rhs]) { this.lhs = lhs this.rhs = rhs } get() { return [this.lhs.get(), this.rhs.get()] } set([lhs, rhs]) { this.lhs.set(lhs) this.rhs.set(rhs) } }
事務(wù)性
獨(dú)立于存儲(chǔ)
全局狀態(tài)的場景 為什么說全局狀態(tài)更好?組件因此可以無狀態(tài)、可以方便地組合
全局狀態(tài)更容易檢查
一切對全局狀態(tài)的操作測試起來都很簡單
全局狀態(tài)是穩(wěn)健的單一數(shù)據(jù)源
為什么不用局部狀態(tài)局部狀態(tài)無法從外部訪問
很難組合
只能間接地去測試局部狀態(tài)
很容易變得散亂
常見的誤解 流(streams)是無狀態(tài)的一般我們認(rèn)為 stream 是無狀態(tài)的,但是請看:
這是無狀態(tài)的嗎?
merge + scan 引入了局部狀態(tài)
組織很容易變得散亂
時(shí)間變得很重要
不過,從好的方便來說:
它可觀察
可以使得依賴更精確:可以方便地觀察「是什么觸發(fā)了這個(gè) stream ?」。
但是沒必要。
任何人都可以修改狀態(tài)將會(huì)是一團(tuán)糟是的,在我們的方案里,任何人得到了一個(gè) state 的分片,都可以修改它。
但是在 calmm 中,我們已經(jīng)
(限定了)作用域
我們通過參數(shù)賦予組件一部分 state,組件只能修改這部分 state,而不是全部
(宣告了)意圖
如果你把可變 state 傳遞給了組件,這相當(dāng)于就宣告說,你允許在這個(gè)組件中修改 state
觀察(了變化)
即使有人修改了 state,組件也能觀察 state 的變化并隨之應(yīng)變。
思考下,你到底想把 state 存儲(chǔ)在哪里?
同時(shí),你的組件如何持久化 state 呢?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91736.html
摘要:真正要做高性能的系統(tǒng),不僅需要在數(shù)據(jù)結(jié)構(gòu)與算法層面深入,更要從硬件操作系統(tǒng)文件系統(tǒng)底層原理等多個(gè)領(lǐng)域做更多的研究例如阿里云自研的系統(tǒng)使用了裸盤技術(shù)。 《CDN之我見》共由三個(gè)篇章組成,分為原理篇、詳解篇和隕坑篇。本篇章適合那些從未接觸過、或僅了解一些 CDN 專業(yè)術(shù)語,想深入了解和感受 CDN 究竟是什么的同學(xué)。本次由白金老師繼續(xù)為大家分享《CDN之我見》系列二,主要講解緩存是什么、工...
摘要:真正要做高性能的系統(tǒng),不僅需要在數(shù)據(jù)結(jié)構(gòu)與算法層面深入,更要從硬件操作系統(tǒng)文件系統(tǒng)底層原理等多個(gè)領(lǐng)域做更多的研究例如阿里云自研的系統(tǒng)使用了裸盤技術(shù)。 《CDN之我見》共由三個(gè)篇章組成,分為原理篇、詳解篇和隕坑篇。本篇章適合那些從未接觸過、或僅了解一些 CDN 專業(yè)術(shù)語,想深入了解和感受 CDN 究竟是什么的同學(xué)。本次由白金老師繼續(xù)為大家分享《CDN之我見》系列二,主要講解緩存是什么、工...
摘要:在我們寫項(xiàng)目代碼的過程中,要經(jīng)常請求接口數(shù)據(jù),在某些異步請求數(shù)據(jù)之后,將得到的值進(jìn)行處理。 在我們寫項(xiàng)目代碼的過程中,要經(jīng)常請求接口數(shù)據(jù),在某些異步請求數(shù)據(jù)之后,將得到的值進(jìn)行處理。通俗的一句話就是,我要把這個(gè)值放到另一個(gè)函數(shù)中,按行數(shù)順序處理,即同步的概念! 例子:第一步,涉及異步函數(shù) 假設(shè)我有一個(gè)函數(shù)abc, function abc(){ //異步方法,請求數(shù)據(jù)得到re...
摘要:通過我們可以更輕松地入門,更簡單的使用的框架。團(tuán)隊(duì)為了擺脫框架中各類繁復(fù)紛雜的配置,使用約定優(yōu)于配置的思想,在基礎(chǔ)上整合了大量常用的第三方庫的開發(fā)框架。這里還要說的一點(diǎn),的出現(xiàn)并不是單純的為了簡化開發(fā),更是為做鋪墊。 說完了Spring 我們來聊聊Spring的進(jìn)階版Spring Boot,如果你還不知道Spring Boot,那希望這篇文章能夠?yàn)槟阒该鞣较颉?Spring Boot ...
摘要:相對于工廠模式,抽象工廠模式生產(chǎn)的對象更加具體,也更加豐富,但相對編碼也更加復(fù)雜。具體的抽象工廠模式的實(shí)現(xiàn)大家可以參考菜鳥教程。知道了工廠模式和抽象工廠模式的區(qū)別,請大家使用的時(shí)候應(yīng)該根據(jù)具體的情況進(jìn)行選擇。 大家好,今天給大家分享一些Spring的學(xué)習(xí)心得,在講Spring之前,先和大家分享Spring中核心的設(shè)計(jì)模式。 工廠模式 在聊概念之前我先問問大家:什么是工廠? 這個(gè)很簡單,...
閱讀 3313·2023-04-25 14:35
閱讀 3427·2021-11-15 18:00
閱讀 2585·2021-11-12 10:34
閱讀 2505·2021-11-11 16:54
閱讀 3489·2021-10-08 10:12
閱讀 2770·2021-09-06 15:02
閱讀 3329·2021-09-04 16:48
閱讀 2806·2019-08-29 14:02