ในโลกของ 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