在 JavaScript 前端開發框架中,Svelte 算是一個新來的攪局者,在網上我們已經聽到很多關於 Svelte 的嗶嗶。因此我決定試試這個家伙,順便跟 React 做個簡單的比較。
本文將展示 Svelte 和 React 在構建一個基礎應用的差異,其中涉及到的內容包括:
組件結構
狀態初始化
屬性傳遞
狀態向上傳遞
事件偵聽
動態樣式
還有很多其他方面的內容需要討論,例如 按需渲染 和 生命周期 等其他炫酷的概念。限於篇幅,這篇文章還是聚焦在基礎使用上吧。
准備工作
在繼續往下閱讀之前,你應該准備好如下環境:
npm 或者 yarn
node.js
如果你用 Visual Studio Code 開發,可以裝一個 Svelte 插件。
Svelte 與 React
Svelte 和 React.js 兩者都是基於組件的 JavaScript 框架,主要用於 Web 應用的開發。最主要的區別是 Svelte 沒有使用虛擬 DOM。Svelte 在構建的時候就將代碼編譯成 Vanilla JS 代碼,而 React 在運行時解釋代碼。
Svelte 文檔寫道:
Svelte 是一種全新的構建 Web 應用的方法。諸如 React 和 Vue 這類傳統的框架,它們的大部分工作都在瀏覽器上執行,而 Svelte 在構建應用的過程做就了大量的工作。
Svelte 沒有使用虛擬 DOM 技術,而是當應用狀態發生變化時,通過代碼如手術般的更新 DOM。
酷!但是這些底層的細節對我來說並不重要。我只想從開發人員的角度看看,在使用 Svelte 和 React 開發應用程序時,感覺好嗎?有趣嗎?直觀嗎?
開工!
創建應用腳手架
在這篇文章中,我們將創建一個很小的 Web 應用,產品經理給這個應用確定了如下需求:
三個組件,分別是:App 、Heading 和 Button
當點擊 Button 時,Heading 會更新顯示點擊的次數
每次點擊 Button 時,Button 自身的顏色會跟着變化
首先使用如下命令在你電腦上創建一個新的目錄,暫且命名為 svelte-react:
mkdir svelte-react
cd svelte-react
接着分別創建 Svelte 和 React 的應用模板並運行。這里 Svelte 的初始步驟比 React 多了一步,此外 Svelte 默認端口是 5000 ,而 React 是 3000 。
Svelte
打開終端窗口,運行如下命令:
npx degit sveltejs/template svelte-test
cd svelte-test
npm install
npm run dev
React
打開第二個終端窗口,進入剛建好的 svelte-react 目錄,運行命令:
npx create-react-app react-test
cd svelte-react
npm start
你會發現 Svelte 的命令運行快得多,因為你不是真正在運行一個工具,而是克隆一個項目模板。
構建應用組件
運行完上述命令后,你會注意到 Svelte 和 React 各自生成很多很多的文件,感興趣的話,可以隨便瀏覽看看這些生成的文件。
不管是 Svelte 和 React ,都是把組件源碼放到 src 文件夾下,Svelte 項目主要是一些擴展名為 svelte 的文件,而 React 項目則是一些 .js 的文件。
兩個項目都有一個 App 組件,分別是 App.svelte 和 App.js 。用你喜好的編輯器分別打開這兩個文件,清空它們,我們從頭開始。
組件結構
Svelte
和 React 組件不同的是,Svelte 的代碼更像是以前我們在寫 HTML、CSS 和 JavaScript 一樣。
所有的 JavaScript 代碼都位於 Svelte 文件頂部的 標簽當中。
然后是 HTML 代碼,你還可以在 標簽中編寫樣式代碼。有趣的是,組件中的樣式代碼只對當前組件有效。這意味着在組件中為
標簽編寫的樣式不會影響到其他組件中的
元素。
接下來我們開始編寫 App.svelte,首先刪空文件內容,然后添加一個空的
我們將在這個標簽中編寫大部分組件代碼。
React
在 React 項目中,打開 App.js 文件,清空所有內容,然后添加如下代碼:
function App() {
}
export default App;
這幾行代碼創建並輸出了一個最基礎的函數式組件,名為 App()https://doc.rust-lang.org/book/ch01-02-hello-world.html 。注意到這里還有另外一個不同之處就是 —— Svelte 無需輸出組件。
Imports
前面我們介紹過這個應用包含三個組件: App, Heading和Button。不管是 Svelte 還是 React ,Heading 和 Button 組件都被引入到 App 中,這樣就可以被當成 App 的子組件使用。我們將在后面繼續編寫這三個組件的代碼,但現在你只需要知道,構建 App 組件時需要引入其他兩個組件。
Svelte
Svelte 需要在
React
React 的 import 語句位於文件的頂部,置於所有的函數或者類定義之前。在 App.js 最頂部,App() 函數之前,添加如下代碼:
import Heading from './Heading.js';
import Button from './Button.js';
import { useState } from 'react';
在這里,React 同時引入了 userState 鈎子,因為 App 是一個有狀態的組件。而 Svelte 不需要這個東西。
狀態初始化
App 是一個有狀態的組件,它有兩個狀態值分別是 color 和 count。
color 表示按鈕的顏色,這個值作為一個屬性傳遞給 Button 組件,並且它在每次點擊按鈕的時候改變。其初始值是 #000000,即為黑色。
count 代表按鈕點擊的次數,其初始值為 0。
Svelte
在 Svelte 中,狀態等同於變量賦值,在 import 語句下方,
React
回到 App.js, 將如下代碼拷貝到你的 App() 函數中狀態聲明部分的下方:
return (
)
該代碼從 App() 函數中返回 UI 界面的 JSX。
這里 Svelte 和 React 的做法都很類似,屬性的傳遞也幾乎相同。而 Svelte 的模板看起來跟 React 的 JSX 很像。
如果你是一個對 Svelte 充滿好奇的 React 開發人員,在屬性傳遞上 Svelte 沒有什么新奇之處。而在接收屬性時 Svelte 有點點不一樣,后面將進行介紹。
狀態向上傳遞
為了讓這個應用正常工作,每次點擊按鈕時,必須讓 App 組件的 count 狀態值增1。因此需要一個機制來將數據從子組件傳遞給父組件。
前面已經通過將 handleClick() 函數作為屬性傳遞給 Button 組件。
接下來馬上要開始編寫的這個屬於 App 組件的函數。當把它作為屬性傳遞給 Button 子組件,Button 組件就能在每次被點擊時調用這個函數。這就是 App 組件能響應其子組件狀態變更的原因。
handleClick() 這個函數負責用來更新 App 組件的count 和 color 狀態值。
Svelte
在 App.svelte 中編寫 handleClick 函數代碼如下:
const colors = ['#00ff00', '#ff0000', '#0000ff'];
let handleClick = () => {
count++;
color = colors[Math.floor(Math.random() * 3)];
}
React
在 App.js 中編寫 handleClick 函數代碼如下:
const colors = ['#00ff00', '#ff0000', '#0000ff'];
let handleClick = () => {
setCount(count+1);
setColor(colors[Math.floor(Math.random() * 3)]);
}
在 React 需要使用早先聲明的 setCount() 和 setColor() 方法來更新狀態值,而 Svelte 則可以直接更新。
現在我們可以開始編寫 Heading 組件了。
編寫 Heading 組件
Heading 組件顯示這個應用的標題以及點擊計數器。這不是一個有狀態的組件,其接收狀態值 count來顯示按鈕點擊次數。
在 Svelte 項目的 src 文件夾中創建一個名為 Heading.svelte 的文件。
同樣的在 React 項目的 src 文件夾中創建新文件 Heading.js.
接收屬性
Svelte
拷貝如下代碼到 Heading.svelte 文件:
Hello, I am a Svelte App!
The following button has been clicked {count} times.
請注意看上述代碼中
上述代碼中兩個屬性都是在頂部的