Leptos คืออะไร? สอนสร้าง Web Frontend ด้วย Rust + WebAssembly ที่เร็วกว่า React 2026
ในโลกของ Web Frontend ที่ React, Vue, Svelte ครองตลาดมานาน มีผู้ท้าชิงรายใหม่ที่กำลังสร้างความตื่นเต้นในวงการ — Leptos Framework ที่สร้างด้วย Rust และ Compile เป็น WebAssembly (Wasm) ให้ประสิทธิภาพที่เร็วกว่า JavaScript Framework แบบเดิมอย่างเห็นได้ชัด
ในปี 2026 Leptos ก้าวสู่เวอร์ชันที่เสถียรพร้อมใช้งานจริง มี Ecosystem ที่เติบโตอย่างรวดเร็ว บทความนี้จะพาคุณทำความรู้จัก Leptos ตั้งแต่พื้นฐาน ระบบ Reactive (Signals) ไปจนถึง SSR + Hydration และเปรียบเทียบกับ Framework อื่นๆ
Leptos คืออะไร?
Leptos เป็น Full-stack Web Framework ที่เขียนด้วยภาษา Rust ออกแบบมาสำหรับสร้าง Web Application ที่ทำงานบน WebAssembly (ฝั่ง Client) และ Native Rust (ฝั่ง Server) มีคุณสมบัติหลักคือ:
- Fine-grained Reactivity: ใช้ระบบ Signals ที่ Update เฉพาะส่วนที่เปลี่ยนแปลง ไม่ต้อง Re-render ทั้ง Component tree เหมือน React (คล้าย SolidJS)
- WebAssembly Performance: Compile Rust เป็น Wasm ทำให้ Runtime performance เร็วกว่า JavaScript มาก
- SSR + Hydration: รองรับ Server-Side Rendering ที่ Render HTML บน Server แล้ว Hydrate บน Client
- Server Functions: เขียน Backend logic ในไฟล์เดียวกับ Frontend ด้วย
#[server]macro - Type Safety: ได้ประโยชน์จาก Rust type system ลด Bug ได้มาก
เริ่มต้น — ติดตั้ง Leptos
# ติดตั้ง Rust (ถ้ายังไม่มี)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# เพิ่ม WebAssembly target
rustup target add wasm32-unknown-unknown
# ติดตั้ง cargo-leptos (Build tool สำหรับ Leptos)
cargo install cargo-leptos
# สร้าง Project ใหม่
cargo leptos new my-leptos-app
cd my-leptos-app
# Run development server
cargo leptos watch
# เปิด http://localhost:3000
Reactive System — Signals, Derived Signals, Effects
Signals — หัวใจของ Leptos
Signal เป็น Reactive primitive ที่เก็บ State เมื่อ Signal เปลี่ยนค่า ทุกส่วนที่ "อ่าน" Signal นั้นจะ Update อัตโนมัติ โดยไม่ต้อง Re-render Component ทั้งหมด:
use leptos::*;
#[component]
fn Counter() -> impl IntoView {
// สร้าง Signal — count เริ่มต้นที่ 0
let (count, set_count) = signal(0);
view! {
// เมื่อ count เปลี่ยน เฉพาะ {count} ที่ Update
// ไม่ใช่ทั้ง Component!
}
}
// เปรียบเทียบกับ React:
// React: useState → setState → Re-render ทั้ง Component
// Leptos: signal → set_signal → Update เฉพาะ DOM node ที่ใช้ Signal
Derived Signals — ค่าที่คำนวณจาก Signal อื่น
#[component]
fn DerivedExample() -> impl IntoView {
let (count, set_count) = signal(0);
// Derived signal — คำนวณอัตโนมัติเมื่อ count เปลี่ยน
let doubled = move || count.get() * 2;
let is_even = move || count.get() % 2 == 0;
view! {
"Doubled: " {doubled}
"Is even: " {is_even}
}
}
Effects — Side Effects
#[component]
fn EffectExample() -> impl IntoView {
let (count, set_count) = signal(0);
// Effect — ทำงานทุกครั้งที่ count เปลี่ยน
Effect::new(move |_| {
log::info!("Count changed to: {}", count.get());
// ทำ Side effect อื่นๆ เช่น API call, localStorage
});
view! {
}
}
Component Model — Function Components
Leptos ใช้ Function components กับ #[component] macro คล้ายกับ React Function components:
// Component ที่รับ Props
#[component]
fn UserCard(
name: String,
#[prop(default = 0)] age: u32,
#[prop(optional)] email: Option<String>,
) -> impl IntoView {
view! {
{name.clone()}
"Age: " {age}
{email.map(|e| view! { "Email: " {e}
})}
}
}
// ใช้งาน
#[component]
fn App() -> impl IntoView {
view! {
}
}
// List rendering ด้วย
#[component]
fn TodoList() -> impl IntoView {
let (todos, set_todos) = signal(vec![
"Learn Rust".to_string(),
"Learn Leptos".to_string(),
"Build Web App".to_string(),
]);
view! {
{todo} }
/>
}
}
SSR + Hydration
Leptos รองรับ Server-Side Rendering แบบเดียวกับ Next.js/Nuxt.js แต่ทำได้ในภาษาเดียว:
// Server Render HTML → ส่งไป Client → Client Hydrate (เพิ่ม Interactivity)
// ใน main.rs
#[cfg(feature = "ssr")]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::*;
use leptos_actix::{generate_route_list, LeptosRoutes};
let conf = get_configuration(None).unwrap();
let routes = generate_route_list(App);
HttpServer::new(move || {
App::new()
.leptos_routes(routes.clone(), App)
.service(Files::new("/", &conf.leptos_options.site_root))
})
.bind("0.0.0.0:3000")?
.run()
.await
}
// Leptos Islands (Partial Hydration)
// เฉพาะ Component ที่ต้อง Interactive จะถูก Hydrate
// ส่วนที่เป็น Static content จะไม่โหลด JavaScript เลย!
#[island]
fn InteractiveCounter() -> impl IntoView {
let (count, set_count) = signal(0);
view! {
}
}
// ใช้ใน Page ที่ส่วนใหญ่เป็น Static
#[component]
fn ArticlePage() -> impl IntoView {
view! {
"Static content... ไม่ต้อง Hydrate ส่วนนี้"
// เฉพาะ Counter ที่ Hydrate
