自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

來自 Rust 生態(tài)的強烈沖擊?談談 Leptos 在語法設計上的精妙之處

開發(fā) 前端
拋開 Rust 的上手難度不談,在語法設計上,Leptos 的語法設計我認為比 Solid 要精妙得多。這是一種更成熟的語法構思。

過去很長一段時間,前端框架們都在往響應式的方向發(fā)展。大家都在基于 signal 實現(xiàn)自己的底層。這種趨勢看上去非?;馃?,給人一種前端框架不往這個方向發(fā)展就落后了一樣。

同時又由于 React hooks 的深遠影響,函數(shù)式 + 響應式成為了不少前端心中最理想的前端框架模樣。Solid 成為了這種模式里最具代表性的框架。

但是,盡管如此,我依然對他保持一種不太愿意接納的態(tài)度,并不是說我對 solid 不熟悉,或者抗拒接受新的知識,其根本原因,還是在語法設計上的問題。

基于響應式能實現(xiàn)細粒度更新,拋去虛擬 DOM 的 diff 成本,性能能夠得到很大的提升。這種設想其實非常美好,但是,在語法設計上會面臨巨大的挑戰(zhàn)。

一、Solid.js

我們來觀察并分析一下 solid.js 在語法設計上存在的問題。

function Counter() {
  const [count, setCount] = createSignal(0)
  return <div onClick={() => setCount(count() + 1)}>
    Count: {count()}
  </div>
}

在這個案例中,我們可以使用 createSignal 創(chuàng)建一個響應式數(shù)據(jù)。這里的問題就在于,返回的響應式數(shù)據(jù) count 他不是一個數(shù)據(jù),而是一個獲取數(shù)據(jù)的 getter 方法。

因為底層基于 Proxy 來實現(xiàn),我們需要監(jiān)聽到數(shù)據(jù)的變化,那么就需要借助 Proxy 中的 getter 方法來實現(xiàn),因此反饋到語法上,count 就只能是一個函數(shù)。

當我們想要將其渲染到 JSX 中時,在 solid 中就將其設計成 {count()}。這里設計成 count() 是沿用了 React 對于 JSX 的理解,想要傳入一個值給 JSX。

當我們在點擊事件中使用該響應式數(shù)據(jù)時。

setCount(count() + 1);

如果你要精準理解 count(),那么理解成本就有點高了,這里的 count() 執(zhí)行,表達了兩層含義。

初始化時,count() 表示會隱式的收集依賴。在跟蹤范圍內,調用 getter 會導致調用 getter 的函數(shù)依賴于對應的 signal。當 signal 更新時,這些依賴都會被重新執(zhí)行。

更新時是依賴重新執(zhí)行,不只是 count() 重新執(zhí)行。許多人理解成 count 重新執(zhí)行,那么在語義上會有更進一步的沖突。

例如:

const double_count = () => count() * 2

// 或者在 jsx 中
<div>count: {count()}</div>

更新時,當我們通過點擊等行為觸發(fā)更新,此時當我們使用 count(),則只是簡單的計算出 count 當前的值。

setCount(count() + 1);

這里其實就是語法設計上的沖突問題。同樣的函數(shù)執(zhí)行,由于編譯手段的強勢侵入,在不同的場景里表達了不同的含義。

其實 solid.js 的開發(fā)團隊也希望 count 就像是直觀表達的那樣,他不是一個 getter,而就是直接是一個值,因此就有類似于如下的語法設計

// 這個時候就變得正常了
setCount((count) => count + 1);

但是很顯然,如果直接完全像 React 那樣符合直覺的語法設計,響應式的能力就得不到保證了。因此這是擁抱響應式不得不做出的犧牲。

Solid 的這個語法割裂,在組件傳參的語法設計中,表現(xiàn)得尤為明顯。

例如你看下面這段代碼,令人意外的是,props.msg 是可以具備響應性的,當我還不熟悉 Solid 的時候直接大吃一驚。

function Message(props: Props) {
  return <div>
    <h1>
      hello, this message is: {props.msg}
    </h1>
    <Child />
  </div>
}

這是擁抱響應式的無奈之舉。因為在組件傳參的時候,其實可能存在兩種類型,一種類型是普通數(shù)據(jù),例如:

<Message msg='hello world' />

而另外一種,就是響應性數(shù)據(jù),例如:

<Message msg={msg()} />

如果我希望一個字段,他可以傳普通類型、也可以傳響應性類型,那么問題就來了,子元素內部如何判斷父組件到底會傳什么類型過來呢?

solid 的解決方案就是,只允許在父組件傳參時,這樣寫 {msg()}。下面這種寫法就會報錯。

<Message msg={msg} />

這樣做的好處就是 solid 可以利用編譯手段去識別 msg() 然后深入子組件內部做依賴收集,從而讓子組件內部不需要做額外的判斷。但是付出的代價就是語法割裂更嚴重了。

除此之外,正因為有黑科技的強勢侵入,因此 solid 中的 JSX 與 React 中的 JSX 表現(xiàn)并完全不一致,也不能按照常規(guī)的表達式去理解。

語法的割裂是我不愿意擁抱 Solid 的主要原因。

二、Leptos

讓我們來看看 rust 生態(tài)中,同樣是基于 signal 來實現(xiàn)的響應式框架 Leptos 是如何在語法設計上解決 solid 的割裂問題的。

首先,一個非常巧妙的設計就是,在 rsx 中,狀態(tài)傳入的括號中,直接接收的就是一個函數(shù)

#[component]
fn App() -> impl IntoView {
  let (count, set_count) = create_signal(0);

  view! {
    <div>{count}</div>
  }
)

這里類似于 React 的 render props

這樣看著就非常的舒服。因為聲明的 count 是一個函數(shù),模板渲染中需要的也是一個函數(shù),語法表現(xiàn)就很一致,按照這個設計,我們就可以不用寫 count() 了。

這個小的語法設計細節(jié)的調整,讓整個語法都變得更加一致。

當我們更新時

set_count.update(|count| *count += 1)

當我們要往子組件中傳遞參數(shù)時

<ProgressBar progress=count />

當語法規(guī)則發(fā)生一些簡單的調整,我們會發(fā)現(xiàn),在大多數(shù)情況下,count 的使用都保持了一致性,而不是像 solid 那樣在不同的場景之下有不同的行為。

當然,如果我們要在邏輯中獲取到 count 的值時,仍然需要使用 count() 來達到目的。不過這在語義上是沒有沖突的。

let double = move || count() * 2;

與 solid 一樣,這段代碼類似于計算屬性,這個匿名函數(shù)也會被收集成為一個依賴,從而讓 double 也具備響應性。

當我們往組件內部傳參數(shù)時,rust 可以通過定義參數(shù)宏來接收和設置參數(shù)的類型、默認值等。

#[component]
pub fn ProgressBar(
  #[prop(default = 100)]
  max: u16,
  #[prop(into)]
  progress: Signal<i32>
) -> impl IntoView {
  view! {
    <progress max=max value=progress />
  }
}

這個東西類似于面向對象中的裝飾器,是給函數(shù)/屬性提供額外能力的一種語法。

他有如下幾種用法。

#[attribute="value"]
#[attribute(key="value")]
#[attribute(value)]

例如,我們將一個普通函數(shù)定義為一個組件,則對該函數(shù)使用如下的宏定義。

#[component]

接收一個參數(shù) max,默認值為 100。

#[prop(default = 100)]
max: u16,

支持任意類型的值傳入,然后調用 .into() 去轉化。

#[prop(into)]
progress: Signal<i32>

因此,有了這個宏的幫助,我們的 progress 屬性可以接收一個響應式屬性,也可以接收一個普通屬性。通過這種方式解決了 solid 在語法設計上面臨的困境。

<ProgressBar progress=count />
<ProgressBar progress=|| 100 />

三、總結

拋開 rust 的上手難度不談,在語法設計上,Leptos 的語法設計我認為比 solid 要精妙得多。這是一種更成熟的語法構思。

但是響應式方案本身在語法上確實存在挑戰(zhàn),例如在 Solid 中還存在更嚴重的問題就是使用解構語法會導致數(shù)據(jù)失去響應性,因此最終也只能靠各種編譯手段盡量抹平差異。但黑科技加多了,一不小心就在重新設計語法了。因此到目前為止,我依然更喜歡 React,他的語法設計足夠簡潔,編譯手段的侵入性足夠小,更符合 JavaScript 的語法邏輯。

責任編輯:姜華 來源: 這波能反殺
相關推薦

2011-05-24 13:33:45

2016-09-09 12:51:23

PhxSQL原則局限性

2021-05-31 07:58:59

Spring設計模式

2014-02-10 10:14:50

MongoDB語法數(shù)據(jù)庫

2021-08-30 09:30:29

Kafka高性能設計

2011-04-15 13:12:09

.NETMEF

2021-10-18 08:28:03

Kafka架構主從架構

2024-08-07 10:18:00

2013-07-15 10:41:28

大數(shù)據(jù)阿里余額寶

2017-03-20 18:03:51

2023-01-05 11:27:27

技術架構

2022-07-17 06:53:24

微服務架構

2017-03-14 15:46:30

AndroidiOS不同之處

2022-06-07 08:31:44

JavaUnsafe

2010-04-20 11:47:46

云計算開源硬件

2022-02-17 15:52:08

區(qū)塊鏈安全技術

2010-05-06 10:09:44

Oracle in

2024-09-30 16:25:40

2018-07-16 14:52:59

無線共存技術

2014-08-07 11:07:32

點贊
收藏

51CTO技術棧公眾號