成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

對于“前端狀態”相關問題,如何思考比較全面

開發 前端
有相當比例的前端從業者入行是從「學習前端框架的使用」開始的。換言之,在他們的知識體系中,最底層是「前端框架如何使用」,其他業務知識都是構建于此之上。

大家好,我卡頌。

最近看到個寫得很不錯的知乎回答Hooks是否過譽了?前端應該跟著React走還是跟著JS、TS走?- beeplin的回答[1]

在這個回答的基礎上,我想引申出一個問題 —— 對于「前端狀態」相關問題,如何思考比較全面?

今天,我們試著從多個抽象層級的角度回答這個問題。

問題的起源

有相當比例的前端從業者入行是從「學習前端框架的使用」開始的。換言之,在他們的知識體系中,最底層是「前端框架如何使用」,其他業務知識都是構建于此之上。

要以此為基礎回答「前端狀態」相關問題,并不容易。就比如你問組長:

  • 為什么項目中用Redux而不用Mobx?
  • 為什么要用Hooks而不用ClassComponent?

很多時候得到的是一個既定的事實(就是這樣,沒有為什么),而不是分析后的結果。

要分析這類問題,我們需要知道一些更低抽象層級的知識。

幾乎所有主流前端框架的實現原理,都在踐行UI = f(state)這個公式,通俗的說 —— 「UI是對狀態的映射」。

這應該是「前端狀態」會出現的最低抽象層級了,所以我們從這個層級出發。

前端框架的實現原理

限于篇幅有限,這里我們以最常見的React與Vue舉例。

在實現「UI是對狀態的映射」過程中,兩者的方向不同。

React?并不關心狀態如何變化。每當調用更新狀態的方法(比如this.setState?,或者useState dispatch?...),就會對整個應用進行diff。

所以在React中,傳遞給「更新狀態的方法」的,是「狀態的快照」,換言之,是個「不可變的數據」。

Vue?關心狀態如何變化。每當更新狀態時,都會對「與狀態關聯的組件」進行diff。

所以在Vue中,是直接改變狀態的值。換言之,狀態是個「可變的數據」。

這種底層實現的區別在單獨使用框架時不會有很大區別,但是會影響上層庫的實現(比如狀態管理庫)。

現在我們知道,通過前端框架,我們可以將狀態映射到UI。那么如何管理好對應的映射關系呢?

換言之,如何將狀態與「和他相關的UI」約束在一起?

我們再往更高一級抽象看。

如何封裝組件

前端開發普遍采用「組件」作為「狀態與UI的松散耦合單元」。

到這里我們可以發現,如果僅僅會使用前端框架,那么只能將組件看作是「前端框架中既定的設計」。

但如果從更低一層抽象(前端框架的實現原理)出發,就能發現 —— 組件是為了解決框架實現原理中「UI到狀態的映射」的途徑。

那么組件該如何實現,他的載體是什么呢?從軟件工程的角度出發,有兩個方向可以探索:

  • 面向對象編程
  • 函數式編程

「面向對象編程」的特點包括:

  • 繼承
  • 封裝
  • 多態

其中「封裝」這一特點使得「面向對象編程」很自然成為組件的首選實現方式,畢竟組件的本質就是「將狀態與UI封裝在一起的松散耦合單元」。

React的ClassComponent,Vue的Options API都是類似實現。

但畢竟組件的本質是「狀態與UI的松散耦合單元」,在考慮復用性時,不僅要考慮「邏輯的復用」(邏輯是指操作狀態的業務代碼),還要考慮「UI的復用」。所以「面向對象編程」的另兩個特性并不適用于組件。

框架們根據自身特點,在「類面向對象編程」的組件實現上,拓展了復用性:

  • React?通過HOC、renderProps
  • Vue2?通過mixin

經過長期實踐,框架們逐漸發現 —— 「類面向對象編程的組件實現」中「封裝」帶來的好處不足以抵消「復用性」上的劣勢。

于是React?引入了Hooks?,以函數作為組件封裝的載體,借用「函數式編程」的理念提高復用性。類似的還有Vue3?中的Composition API。

不管是ClassComponent?還是FunctionComponent?、Options API?還是Composition API,他們的本質都是「狀態與UI的松散耦合單元」。

當組件數量增多,邏輯變復雜時,一種常見的解耦方式是 —— 將可復用的邏輯從組件中抽離出來,放到單獨的Model?層。UI?直接調用Model層的方法。

對Model層的管理,也就是所謂的「狀態管理」。

對狀態的管理,是比組件中「狀態與UI的耦合」更高一級的抽象。

狀態管理問題

?狀態管理」要考慮的最基本的問題是 —— 如何與框架實現原理盡可能契合?

比如,我們要設計一個User Model?,如果用class的形式書寫:

class User {
name: String;
constructor(name: string) {
this.name = name;
}
changeName(name: string) {
return this.name = name;
}
}

只需要將這個Model的實例包裝為響應式對象,就能很方便的接入Vue3:

import { reactive } from 'vue'

setup() {
const user = reactive(new User('KaSong') as User;
return () (
<button onClick={() => user.changeName('XiaoMing')}>
{user.name}
</button>
)
}

之所以這么方便,誠如本文開篇提到的 —— Vue?的實現原理中,狀態是「可變的數據」,這與User Model的用法是契合的。

同樣的User Model?要接入React?則比較困難,因為React原生支持的是「不可變數據」類型的狀態。

要接入React?,我們可以將同樣的User Model?設計為不可變數據,采用reducer的形式書寫:

const userModel = {
name: 'KaSong'
};

const userReducer = (state, action) => {
switch (action.type) {
case "changeName":
const name = action.payload;
return {...state, name}
}
};

function App() {
const [user, dispatch] = useReducer(userReducer, userModel);

const changeName = (name) => {
dispatch({type: "changeName", payload: name});
};

return (
<button onClick={() => changeName('XiaoMing')}>
{user.name}
</button>
);
}

如果一定要接入「可變類型狀態」,可以為React?提供類似Vue?的「響應式更新」能力后再接入。比如借用Mobx提供的響應式能力:

import { makeAutoObservable } from "mobx"

function createUser(name) {
return makeAutoObservable(new User(name));
}

到目前為止,不管是「可變類型狀態」還是「不可變類型狀態」的Model,都帶來了「從組件中抽離邏輯」的能力,對于上例來說:

  • 「可變類型狀態」將狀態與邏輯抽離到User中
  • 「不可變類型狀態」將狀態與邏輯抽離到userModel與userReducer
  • 最終暴露給UI的都僅僅是changeName方法

當業務進一步復雜,Model本身需要更完善的架構,此時又是更高一級的抽象。

到這一層時已經脫離前端框架的范疇,上升到純狀態的管理,比如為mobx?帶來結構化數據的mobx-state-tree。

此時框架實現原理對Model?的影響已經在更高的抽象中被抹去了,比如Redux-toolkit?是React?技術棧的解決方案,Vuex?是Vue技術棧的解決方案,但他們在使用方式上是類似的。

這是因為Redux與Vuex的理念都借鑒自Flux,即使React與Vue在實現原理上有區別,但這些區別都被狀態管理方案抹平了。

更高的抽象

在此之上,對于狀態還有沒有更高的抽象呢?答案是肯定的。

對于常規的狀態管理方案,根據用途不同,可以劃分出更多細分領域,比如:

  • 對于表單狀態,收斂到表單狀態管理庫中。
  • 對于服務端緩存,收斂到服務端狀態管理庫中(React Query、SWR)。
  • 用完整的框架收斂前后端Model,比如Remix、Next.js。

總結

回到我們開篇提到的問題:

  • 為什么項目中用Redux而不用Mobx?
  • 為什么要用Hooks而不用ClassComponent?

現在我們已經能清晰的知道這兩個問題的相同點與不同點:

  • 相同點:都與狀態相關。
  • 不同點:屬于不同抽象層級的狀態相關問題。

要回答這些問題需要哪些知識呢?只需要知道問題涉及的「狀態的抽象層級」,以及「比該層級更低的抽象層級」對應的知識即可。

比如回答:為什么項目中用Redux?而不用Mobx?

考慮當前抽象層級

Redux與Mobx?都屬于Model?的實現,前者帶來一套「類Flux的狀態管理理念」,后者為React?帶來「響應式更新」能力,在設計Model時我的項目更適合哪種類型?

或者兩種類型我都不在乎,那么要不要使用更高抽象的解決方案(比如MST、Redux Toolkit)抹平這些差異?

考慮低一級抽象層級

項目用的ClassComponent還是FunctionComponent?Redux、Mobx與他們結合使用時哪個組合更能協調好UI與邏輯的松散耦合?

考慮再低一級抽象層級

React?的實現原理決定了他原生與「不可變類型狀態」更親和。Redux?更契合「不可變數據」,Mobx更契合「可變數據」。我的項目需要考慮這些差異么?

當了解不同抽象層級需要考慮的問題后,任何寬泛的、狀態相關問題都能轉化成具體的、多抽象層級問題。

從不同抽象層級出發思考,就能更全面的回答問題。

參考資料

[1]Hooks是否過譽了?前端應該跟著React走還是跟著JS、TS走?- beeplin的回答:https://www.zhihu.com/question/468249924/answer/1968728853。

責任編輯:姜華 來源: 魔術師卡頌
相關推薦

2017-07-10 14:53:35

前端開發MVVM模式有限狀態機

2021-04-29 09:31:05

前端開發技術

2019-12-16 08:00:00

ReactAngularVue

2009-12-03 18:09:51

Visual Stud

2010-09-10 15:18:28

SOAP協議

2009-06-25 09:50:32

JSF

2021-05-12 06:28:09

AI人工智能

2020-12-23 07:56:40

前端UICSS

2009-07-15 16:39:51

AWT和Swing

2009-07-14 16:30:41

Swing與SWT

2009-06-26 14:37:10

EJB和Spring

2009-06-24 16:16:30

JSF和Tapestr

2011-08-01 10:37:29

軟件項目管理

2009-12-22 15:08:46

ADO控件

2009-12-28 17:01:31

2020-07-07 07:00:00

RustGo語言編程語言

2009-08-18 10:24:03

Java開發工具

2009-10-28 13:27:11

2009-08-11 14:57:11

比較C#和Java

2024-05-22 10:03:59

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一二三区 | 欧美第一页 | 欧美日韩黄色一级片 | 国产成人小视频 | 一区二区视屏 | 亚洲午夜精品一区二区三区他趣 | 国产综合在线视频 | 精品福利在线 | 二区精品 | av毛片| 超碰成人免费 | 久久草在线视频 | 毛片免费视频 | 国内精品伊人久久久久网站 | 又黄又色 | 午夜影院| 久久久久久久久综合 | 一区二区在线不卡 | 狠狠爱免费视频 | 日韩一二区 | 成人亚洲性情网站www在线观看 | 国产精品久久久久久一级毛片 | 亚洲国产成人av好男人在线观看 | 一区二区精品 | 久草a√ | 成人在线中文字幕 | 欧美久久一区二区三区 | 日韩美女一区二区三区在线观看 | 成人在线视频免费观看 | 日韩亚洲一区二区 | 日韩色图视频 | 久久免费精品视频 | 日韩免费视频一区二区 | 亚洲精品68久久久一区 | 久久香蕉网 | 亚洲福利在线视频 | 精品一区二区免费视频 | 国产十日韩十欧美 | 中文字幕av在线 | 欧美一区二区三区在线视频 | 色综合激情 |