Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

Svelte 5 và Signal-Based Reactivity: Lý Do Dev Web Đang Theo Dõi Sát

Ếch Trendy
Ếch Trendy

4 tháng trước · 10 phút đọc

Svelte không dùng virtual DOM - và đó chính là điểm khác biệt

Mình nhớ lần đầu thử Svelte sau vài năm chỉ biết React. Cảm giác kỳ lạ nhất không phải là cú pháp mới, mà là cái sự... vắng lặng. Không có useState, không có dependency array, không có cái cảm giác cần phải "khai báo đúng chỗ" để tránh bug stale closure.

Svelte là một compile-time framework: thay vì gửi cả đống logic framework xuống trình duyệt để xử lý lúc runtime, Svelte chuyển phần lớn công việc đó vào bước build. Compiler phân tích component bạn viết, nhìn vào chỗ nào dùng biến nào, rồi sinh ra JavaScript tối ưu để thao tác DOM trực tiếp.

Kết quả? Bundle nhỏ hơn đáng kể, không có lớp virtual DOM ở giữa, và code gần với HTML/CSS/JS thuần hơn nhiều.

344653 Svelte biên dịch component thành DOM updates tối ưu, bỏ qua virtual DOM hoàn toàn

React giải quyết vấn đề UI update bằng cách duy trì một cây virtual DOM rồi diff với DOM thật. Cách này hoạt động tốt nhưng có overhead nhất định. Svelte chọn hướng khác: giải quyết ở compile time, không cần runtime reconciliation.

Đây không phải là Svelte tốt hơn React về mọi mặt. Đây là hai cách tiếp cận khác nhau cho cùng một vấn đề, và hiểu sự khác biệt này giúp bạn chọn đúng tool.


Runes: signal-based reactivity trông như thế nào trong thực tế

Svelte 5 giới thiệu runes - cách khai báo state và reactivity mới hoàn toàn. Ba runes quan trọng nhất:

<script>
  // Khai báo state phản ứng
  let count = $state(0);

  // Giá trị tính toán từ state khác (tự động cập nhật)
  let doubled = $derived(count * 2);

  // Side effect sau khi render
  $effect(() => {
    console.log('count thay đổi:', count);
  });
</script>

<button onclick={() => count++}>
  Đếm: {count} (gấp đôi: {doubled})
</button>

So sánh với cách viết tương đương trong React:

import { useState, useMemo, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  // Phải khai báo dependency array tường minh
  const doubled = useMemo(() => count * 2, [count]);

  // Phải khai báo dependency array, dễ quên
  useEffect(() => {
    console.log('count thay đổi:', count);
  }, [count]);

  return (
    <button onClick={() => setCount(c => c + 1)}>
      Đếm: {count} (gấp đôi: {doubled})
    </button>
  );
}

Cùng một logic, Svelte cần ít code hơn và không cần dependency array

Vấn đề với React hooks không phải là chúng phức tạp - mà là bạn phải liên tục nhớ khai báo dependency array đúng. Quên thêm một dependency? Stale closure. Thêm thừa? Effect chạy không cần thiết. Đây là nguồn gốc của vô số bug khó debug.

Svelte 5 với $derived và $effect tự động theo dõi dependency. Bạn không cần khai báo gì thêm - compiler hiểu rằng doubled phụ thuộc vào count vì count xuất hiện trong biểu thức. Reactivity trở nên minh bạch hơn và gần với cách người ta nghĩ về dữ liệu hơn.

Tất nhiên có trade-off: mô hình này hoạt động tốt nhất khi dependency đơn giản. Với logic phức tạp, async, hoặc cross-component state phức tạp, bạn vẫn cần hiểu rõ compiler đang làm gì.


"Signal" trong signal-based reactivity nghĩa là gì

Thuật ngữ "signal" đang xuất hiện khắp nơi trong cộng đồng frontend - từ SolidJS, Angular Signals, cho đến cách Svelte 5 mô tả runes. Thực ra ý tưởng không mới, nhưng cách implement ngày càng rõ ràng hơn.

Signal là một đơn vị state có khả năng thông báo khi giá trị thay đổi. Bất cứ thứ gì "subscribe" vào signal đó sẽ tự động cập nhật. Khác với React, nơi component re-render theo cấu trúc cây (parent render thì child render theo), signal chỉ cập nhật đúng phần UI phụ thuộc vào state đó.

344654 Signal chỉ update đúng component phụ thuộc, không phải toàn bộ cây

Trong Svelte 5, $state tạo ra một reactive value. Compiler phân tích template để biết chỗ nào dùng value đó, rồi sinh code cập nhật đúng chỗ đó khi value thay đổi. Kết quả gần với cách signal hoạt động trong SolidJS, nhưng được tích hợp ở compiler level thay vì runtime.

Điều này giải thích tại sao nhiều dev đang chú ý đến Svelte 5: nó đang đi theo một hướng mà cả Angular, SolidJS, và ngay cả Vue (với Composition API) đang đi, nhưng với approach biên dịch độc đáo hơn. "Signal-based" không chỉ là buzzword - nó mô tả một mô hình reactivity rõ ràng và predictable hơn so với kiểu "implicit magic" mà Svelte cũ từng dùng.

Nếu bạn đang học JavaScript và muốn hiểu sâu hơn về cách reactivity hoạt động ở mức nền tảng, khóa Lập Trình JavaScript Nâng Cao cover các concept như closure, reference types - những thứ giúp bạn hiểu tại sao dependency array trong React dễ bị sai.


Svelte phù hợp nhất khi nào

Mình không nói Svelte thay thế React. Nhưng có những tình huống cụ thể mà Svelte là lựa chọn rõ ràng hơn.

Dự án nhỏ đến vừa với team ít người là môi trường Svelte tỏa sáng nhất. Khi bạn build một dashboard nội bộ, admin panel, marketing site, hoặc SaaS nhỏ, bạn muốn ship nhanh và dễ bảo trì. Ít boilerplate = ít code = ít bug tiềm ẩn.

Prototype và MVP là use case khác. Mô hình code ngắn, reactivity tự nhiên giúp rút ngắn thời gian dựng MVP đáng kể. Bạn viết ít code hơn để đạt cùng kết quả.

344655 Ba tình huống Svelte phù hợp rõ nhất trong thực tế

Khi performance bundle size quan trọng - ứng dụng cần load nhanh, chạy trên thiết bị yếu, hoặc cần phản hồi tốt với animation và interaction phức tạp. Svelte không kéo theo runtime framework lớn.

Ngược lại, Svelte không phải lựa chọn tốt khi:

  • Team đã có codebase React lớn và đang hoạt động tốt
  • Cần hệ sinh thái khổng lồ (React Native, Next.js ecosystem rộng, hàng ngàn thư viện)
  • Team hire dễ hơn với React experience (thị trường việc làm Svelte vẫn nhỏ hơn nhiều)
  • Ứng dụng cực kỳ phức tạp với state management enterprise-level

Về meta-framework, SvelteKit là đối tác chính thức cho routing, SSR, và các tính năng web app hiện đại - tương tự cách Next.js đứng cạnh React. Nếu bạn đang cân nhắc Svelte cho dự án thực tế, SvelteKit là con đường bạn sẽ đi.

Một điểm đáng chú ý: MDN nhận xét Svelte giữ gần với HTML, CSS, JS truyền thống và có thể dễ tiếp cận hơn với người ít kinh nghiệm với tooling hiện đại. Nếu bạn đã vững HTML/CSS cơ bản, entry barrier vào Svelte thấp hơn React đáng kể.


Thực hành: xây một counter đơn giản với Svelte 5 runes

Lý thuyết đủ rồi. Nhìn vào code thực tế:

<script>
  // State cơ bản
  let count = $state(0);
  let step = $state(1);

  // Derived value - tự động tính lại khi count hoặc step thay đổi
  let nextValue = $derived(count + step);
  let isNegative = $derived(count < 0);

  // Effect - chạy mỗi khi count thay đổi
  $effect(() => {
    document.title = `Đếm: ${count}`;
  });

  function increment() {
    count += step; // Gán trực tiếp - không cần setter function
  }

  function reset() {
    count = 0;
  }
</script>

<div class="counter">
  <p class:negative={isNegative}>{count}</p>
  <p>Giá trị tiếp theo: {nextValue}</p>

  <label>
    Bước nhảy:
    <input type="number" bind:value={step} />
  </label>

  <button onclick={increment}>+{step}</button>
  <button onclick={reset}>Reset</button>
</div>

<style>
  .negative { color: red; }
</style>

344656 Gán trực tiếp count += step thay vì setCount(c => c + step) - code gọn hơn thật

Vài điểm đáng chú ý:

  • count += step thay vì setCount(prev => prev + step) - viết tự nhiên như JS thuần
  • $derived không cần dependency array - compiler tự hiểu
  • bind:value={step} two-way binding trực tiếp cho input - Svelte cho phép, React không khuyến khích
  • CSS scoped tự động trong <style> - không cần CSS modules hay styled-components

Snippets là một tính năng mới khác trong Svelte 5, cho phép tái sử dụng đoạn UI template bên trong component mà không cần tách thành component riêng. Hữu ích khi bạn có pattern lặp lại nhiều lần trong cùng một file.

Nếu bạn muốn tải về file demo interactive để thử ngay trong trình duyệt (không cần setup): Tải file demo counter interactive


Hệ sinh thái Svelte 5 hiện tại đang ở đâu

Một câu hỏi thực tế: Svelte có đủ "chín" để dùng cho production chưa?

Svelte 5 đang ở nhánh 5.x với các cập nhật liên tục. Bản mới nhất theo dõi được là 5.56.1 (tháng 6/2026). Blog chính thức của Svelte vẫn đang cập nhật đều đặn trong 2026 với các tính năng như better forms, TypeScript 6 support trong language-tools, và new long-lived remote query APIs. Không có dấu hiệu của một "Svelte 6" đang được định hình - hướng phát triển hiện tại vẫn là mở rộng Svelte 5.x.

344657 Svelte 5.x vẫn đang được cập nhật tích cực - không phải framework bị bỏ quên

Về hệ sinh thái:

  • SvelteKit ổn định và production-ready cho web apps
  • VS Code extension và language-tools hỗ trợ tốt
  • TypeScript được support đầy đủ
  • Community nhỏ hơn React/Vue nhưng active
  • Thư viện UI: Skeleton UI, Flowbite Svelte, shadcn-svelte đang phát triển

Trade-off thực tế: nếu bạn gặp edge case phức tạp, khả năng tìm được Stack Overflow answer hoặc GitHub issue tương ứng thấp hơn React. Đây là cái giá của một hệ sinh thái nhỏ hơn.

Mình nghĩ Svelte đáng học vì lý do khác ngoài "để thay thế React": nó buộc bạn nghĩ khác về reactivity. Sau khi viết Svelte một thời gian, bạn sẽ nhìn React hooks với con mắt rõ hơn - hiểu tại sao dependency array tồn tại, tại sao useMemo là cần thiết, và khi nào không cần.

Nếu bạn chưa vững JavaScript cơ bản trước khi nhảy vào Svelte hay React, khóa Lập Trình JavaScript Cơ Bản là điểm khởi đầu tốt.

Bước tiếp theo nếu bạn muốn thử:

  1. Chạy npx sv create my-app để tạo project SvelteKit mới
  2. Viết 1 component đơn giản với $state và $derived
  3. So sánh trực tiếp với cách bạn viết React tương đương

Gặp vướng mắc hay muốn chia sẻ trải nghiệm, drop comment nhé.

Trang web dùng cookie để hoạt động và đo hiệu quả quảng cáo. Xem chính sách bảo mật