Skip to content

dat-dv/redux-like

Repository files navigation

Redux Implementation (From Scratch) 🛠️

Project này được xây dựng để hiểu rõ bản chất cơ chế hoạt động bên trong của Redux, thay vì chỉ sử dụng nó.

🎯 Mục đích chính

Mục tiêu cốt lõi là giải mã các câu hỏi:

  • State nằm ở đâu?: Hiểu bản chất của nguồn dữ liệu duy nhất (Single Source of Truth).
  • Làm sao UI tự cập nhật?: Hiểu cơ chế Observer Pattern (đăng ký/lắng nghe) của hàm subscribe.
  • React kết nối Redux thế nào?: Thấy rõ vai trò của Context API trong Provider và cách các hook như useSelector truy xuất dữ liệu.

💡 Bài học kinh nghiệm (Lessons Learned)

Quá trình tự xây dựng giúp rút ra những bài học quan trọng:

1. Tại sao phải Bất Biến (Immutability)?

Redux dựa trên việc so sánh tham chiếu (===) để tối ưu hiệu năng. Hàm useSelector chúng ta viết sẽ kiểm tra oldState === newState. Nếu sửa trực tiếp vào object cũ (mutate), tham chiếu không đổi nên React sẽ không render lại. Do đó, bắt buộc phải trả về object mới (copy & spread ...state) để kích hoạt cập nhật UI.

2. Vấn đề Stale Closure (Closure bị cũ)

Khi viết hook, chúng ta dễ gặp trường hợp hàm subscribe bên trong useEffect ghi nhớ state cũ tại thời điểm nó được tạo ra. -> Giải pháp: Cần xử lý dependency array cẩn thận hoặc gọi trực tiếp store.getState() bên trong callback để luôn đảm bảo lấy được dữ liệu mới nhất.

3. Vấn đề Tham Chiếu Selector (Selector Reference)

Trong hook useSelector tự viết, một vấn đề hiệu năng nảy sinh khi ta sử dụng inline function (ví dụ: useSelector(state => state.count)). Mỗi lần component render, Javascript sẽ tạo ra một function mới -> tham chiếu thay đổi. Nếu ta đưa selector vào dependency array của useEffect, nó sẽ khiến quá trình hủy đăng ký và đăng ký lại (unsubscribe/subscribe) diễn ra liên tục. -> Thực tế: Các thư viện chuẩn giải quyết việc này bằng cách dùng useRef để giữ tham chiếu ổn định hoặc sử dụng API mới useSyncExternalStore.

4. Vấn đề "Tearing UI" trong React 18

Cách dùng useEffect để subscribe rất dễ hiểu, nhưng chưa an toàn tuyệt đối trong chế độ Concurrent của React 18. Nếu React đang render dở dang (render ngắt quãng) mà Store bất ngờ thay đổi dữ liệu, giao diện có thể bị "rách" (phần trên hiển thị số mới, phần dưới vẫn số cũ). -> Thực tế: Đây là lý do React 18 đẻ ra hook useSyncExternalStore để đảm bảo tính nhất quán (consistency) cho các thư viện state bên ngoài như Redux.

5. Chi phí lan truyền (Broadcast Overhead)

Hệ thống Pub/Sub của chúng ta hoạt động theo kiểu: "Có biến -> Báo cho TẤT CẢ". Điều này nghĩa là nếu app có 1000 component kết nối Redux, mỗi khi dispatch 1 action (dù rất nhỏ), cả 1000 component đều phải tỉnh dậy để chạy hàm selector kiểm tra. -> Bài học: Selector phải tính toán cực nhanh và nhẹ. Nếu nhét logic nặng vào selector, mỗi cú click chuột có thể làm treo cả ứng dụng.

-> Redux hoàn toàn có thể custom được hàm so sánh equality để quyết định có rerender hay không.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors