SwiftUI之从前端视角看SwiftUI语言
生活随笔
收集整理的這篇文章主要介紹了
SwiftUI之从前端视角看SwiftUI语言
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、從 class 邁向 struct,從 class 邁向 function
- 可以將前端框架歸納為幾個(gè)要素:
-
- 元件化;
-
- 響應(yīng)式機(jī)制;
-
- 狀態(tài)管理;
-
- 事件監(jiān)聽;
-
- 生命周期。
- 在寫 SwiftUI 的時(shí)候總是想到 React 的發(fā)展史,最初 React 建立元件的方式是透過 JavaScript 的 class 語法,每個(gè) React 的元件都是一個(gè)類別。
- 透過類別定義元件雖為前端元件化帶來了很大的影響,但也因?yàn)榉爆嵉姆椒ǘx與 this 混淆,在 React16 hooks 出現(xiàn)之后,逐漸提倡使用 function component 與 hooks 的方式來建立元件。
- 省去了繼承與各種 OO 的花式設(shè)計(jì)模式,建構(gòu)元件的心智負(fù)擔(dān)變得更小了。從 SwiftUI 當(dāng)中,也可以看到類似的演進(jìn),原本 ViewController 龐大的 class 以及職責(zé),要負(fù)責(zé) view 與 model 的互動(dòng),掌管生命周期,轉(zhuǎn)為更輕量的 struct,讓開發(fā)者可以更專注在 UI 互動(dòng)上,減輕認(rèn)知負(fù)擔(dān)。
二、元件狀態(tài)管理
- React 16 采取了 hooks 來做元件的邏輯復(fù)用與狀態(tài)管理,例如 useState:
- 在 SwiftUI 當(dāng)中,可以透過修飾符 @State 讓 View 也具有類似效果。兩者都具備響應(yīng)式機(jī)制,當(dāng)狀態(tài)變數(shù)發(fā)生改變時(shí),React/Vue 會(huì)偵測改變并反映到畫面當(dāng)中。雖然不知道 SwiftUI 背后的實(shí)作,但背后應(yīng)該也有類似 diff 機(jī)制的東西來達(dá)到響應(yīng)式機(jī)制與最小更新的效果。
- 然而 SwiftUI 的狀態(tài)管理與 React hooks 仍有差異,在 React 當(dāng)中,可以將 hook 拆成獨(dú)立的函數(shù),并且在不同的元件當(dāng)中使用,例如:
- 在 React 當(dāng)中,可以將 toggle 的邏輯拆出,并在不同元件之間使用,由于 useToggle 是一個(gè)純函數(shù),因此內(nèi)部的狀態(tài)也不會(huì)互相影響。
- 然而在 SwiftUI 當(dāng)中 @State 只能作用在 struct 的 private var 當(dāng)中,不能進(jìn)一步拆出。如果想要將重復(fù)的邏輯抽出,需要另外使用 @Observable 與 @StateObject 這樣的修飾符,另外建立一個(gè)類別來處理。
- 在這個(gè)例子當(dāng)中把 toggle 的邏輯拆成一個(gè) class 似乎有點(diǎn)小題大作了,不過仔細(xì)想想像 React 提供的 hook 功能,讓輕量的邏輯共用就算單獨(dú)拆成 hook 也不會(huì)覺得過于冗長,若要封裝更復(fù)雜的邏輯也可以再拆分成更多 hooks,從這點(diǎn)來看 hook 的確是一個(gè)相當(dāng)優(yōu)秀的機(jī)制。后來看到了 SwiftUI-Hooks,不知道實(shí)際使用的效果如何。
- 以 React 來說,在還沒有出現(xiàn) hooks 之前,主要有三個(gè)方式來實(shí)作邏輯共用:
-
- HOC(Higher Order Component):將共同邏輯包裝成函數(shù)后返回全新的 class,避免直接修改元件內(nèi)部的實(shí)作,例如早期 react-redux 中的 connect;
-
- render props:將實(shí)際渲染的元件當(dāng)作屬性(props)傳入,并提供必要的參數(shù)供實(shí)作端使用;
-
- children function:children 只傳入必要的參數(shù),由實(shí)作端自行決定要渲染的元件。
三、Redux 與 TCA
- 受到 Redux 的影響,在 Swift 當(dāng)中也有部分開發(fā)者使用了采用了類似手法,甚至也有相對(duì)應(yīng)的實(shí)作 ReSwift 的說明文。從說明文可以看到主要原因,傳統(tǒng)的 ViewController 職責(zé)曖昧,容易變得肥大導(dǎo)致難以維護(hù),透過 Reducer、Action、Store 訂閱來確保單向資料流,所有的操作都是向 store dispatch 一個(gè) action,而資料的改動(dòng)(mutation)則在 reducer 處理。
- 而最近的趨勢(shì)似乎從 Redux 演變成了 TCA(The Composable Architecture),跟 Redux 的中心思想類似,更容易與 SwiftUI 整合,比較不一樣的地方在于以往涉及 side effect 的操作在 Redux 當(dāng)中會(huì)統(tǒng)一由 middleware 處理,而在 TCA 的架構(gòu)中 reducer 可以回傳一個(gè) Effect,代表接收 action 時(shí)所要執(zhí)行的 IO 操作或是 API 呼叫。
- 既然采用了類似 redux 的手法,不知道 SwiftUI 是否會(huì)遇到與前端開發(fā)類似的問題,例如 immutability 確保更新可以被感知;透過優(yōu)化 subscribe 機(jī)制確保 store 更新時(shí)只有對(duì)應(yīng)的元件會(huì)更新;reducer 與 action 帶來的 boilerplate 問題。
- 雖然 Redux 在前端仍然具有一定地位,也仍然有許多公司正在導(dǎo)入,然而在前端也越來越多棄用 Redux 的聲音,主要因?yàn)?redux 對(duì) pure function 的追求以及 reducer、action 的重復(fù)性極高,在應(yīng)用沒有到一定復(fù)雜程度之前很難看出帶來的好處,甚至連 Redux 作者本人也開始棄坑 redux 了 4。與此同時(shí),react-redux 仍然有在持續(xù)更新,也推出了 redux-toolkit 來試圖解決導(dǎo)入 redux 時(shí)常見的問題。
- 取而代之的是更加輕量的狀態(tài)管理機(jī)制,在前端也衍生出了幾個(gè)流派:
-
- GraphQL → 使用 apollo 或是 relay;
-
- react-query;
-
- react-swr;
-
- recoil;
-
- jotai。
四、全域狀態(tài)管理
- 在全域狀態(tài)管理上,SwiftUI 也有內(nèi)建機(jī)制叫做 @EnvrionmentObject,其運(yùn)作機(jī)制很像 React 的 context,讓元件可以跨階層存取變數(shù),當(dāng) context 改變時(shí)也會(huì)更新元件:
- 從上面這個(gè)范例可以發(fā)現(xiàn),不需要另外傳入 user 給 UserInfo,透過 @EnvrionmentObject 可以拿到當(dāng)前的 context。轉(zhuǎn)換成 React 的話會(huì)像這樣:
- React 的 context 可讓元件跨階層存取變數(shù),當(dāng) context 改變時(shí)也會(huì)更新元件。雖然有效避免了 prop drilling 的問題,然而 context 的存在會(huì)讓測試比較麻煩一些,因?yàn)槭褂?context 時(shí)代表了某種程度的耦合。
五、響應(yīng)機(jī)制
- 在 React 當(dāng)中,狀態(tài)或是 props 有變動(dòng)時(shí)都會(huì)觸發(fā)元件更新,透過框架實(shí)作的 diff 機(jī)制比較后反映到畫面上。在 SwfitUI 中也可以看到類似的機(jī)制:
- 一個(gè)典型的 SwiftUI 元件是一個(gè) struct,透過定義 body 變數(shù)來決定 UI。跟 React 相同,它們都只是對(duì) UI 的抽象描述,透過比對(duì)資料結(jié)構(gòu)計(jì)算最小差異后,再更新到畫面上。
- @State 修飾符可用來定義元件內(nèi)部狀態(tài),當(dāng)狀態(tài)改變時(shí)會(huì)更新并反映到畫面中。在 SwiftUI 當(dāng)中,屬性(MyView 當(dāng)中的 name)可以由外部傳入,跟 React 當(dāng)中的屬性(props)類似。
- 用 React 改寫這個(gè)元件的話會(huì)像這樣:
- 在撰寫 SwiftUI 時(shí)會(huì)發(fā)現(xiàn)這跟以往用 UIKit、UIController 的開發(fā)方式不太一樣。
六、列表
- SwiftUI 與 React 當(dāng)中都可以渲染列表,而撰寫的方式也有雷同之處。在 SwiftUI 當(dāng)中可以這樣寫:
- 轉(zhuǎn)成 React 大概會(huì)像這樣子:
- 在渲染列表時(shí)為了確保效能,減少不必要的比對(duì),React 會(huì)要求開發(fā)者提供 key,而在 SwiftUI 當(dāng)中也有類似的機(jī)制,開發(fā)者必須使用叫做 Identifiable[11] 的 protocol,或是顯式地傳入 id。
七、Binding
- 除了將變數(shù)綁定到畫面之外,也可以將互動(dòng)綁定到變數(shù)之中。例如在 SwiftUI 當(dāng)中我們可以這樣寫:
- 在這個(gè)范例當(dāng)中,就算不監(jiān)聽輸入事件,使用 $text 也可以直接改變 text 變數(shù),當(dāng)使用 @State 時(shí)會(huì)加入 property wrapper,會(huì)自動(dòng)加入一個(gè)前綴 $,型別為 Binding。
- React 并沒有雙向綁定機(jī)制,必須要顯式監(jiān)聽輸入事件確保單向資料流。不過像 Vue、Svelte 都有雙向綁定機(jī)制,節(jié)省開發(fā)者手動(dòng)監(jiān)聽事件的成本。
八、Combine 的出現(xiàn)
- 雖然我對(duì) Combine 還不夠熟悉,但從官方文件與影片看起來,很像RxJS 的 Swift 特化版,提供的 API 與操作符大幅度地簡化了復(fù)雜資料流。這讓我想起了以前研究 RxJS 與 redux-observable 各種花式操作的時(shí)光,真令人懷念。
九、總結(jié)
- 前文提到那么多,然而網(wǎng)頁與手機(jī)開發(fā)仍然有相當(dāng)大的差異,其中對(duì)我來說最顯著的一點(diǎn)是靜態(tài)編譯與動(dòng)態(tài)執(zhí)行。動(dòng)態(tài)執(zhí)行可以說是網(wǎng)頁最大的特色之一。
- 只要有瀏覽器,JavaScript、HTML、CSS,不管在任何裝置上都可以成功執(zhí)行,網(wǎng)頁不需要事先下載 1xMB ~ 幾百 MB 的內(nèi)容,可以動(dòng)態(tài)執(zhí)行腳本,根據(jù)瀏覽的頁面動(dòng)態(tài)載入內(nèi)容。
- 由于不需要事先編譯,任何人都可以看到網(wǎng)頁的內(nèi)容與執(zhí)行腳本,加上 HTML 可以 streaming 的特性,可以一邊渲染一邊讀取內(nèi)容。難能可貴的一點(diǎn)是,網(wǎng)頁是去中心化的,只要有伺服器、ip 位址與網(wǎng)域,任何人都可以存取網(wǎng)站內(nèi)容;而 App 如果要上架必須事先通過審查。
- 不過兩者的生態(tài)圈與開發(fā)手法有很大的不同,仍然建議參考一下彼此的發(fā)展,就算平時(shí)不會(huì)碰也沒關(guān)系,從不同的角度看往往可以發(fā)現(xiàn)不同的事情,也可以培養(yǎng)對(duì)技術(shù)的敏銳度。
總結(jié)
以上是生活随笔為你收集整理的SwiftUI之从前端视角看SwiftUI语言的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数据结构与算法】之深入解析“格雷编码”
- 下一篇: Putty基础教程之(一).入门命令学习