Tại sao nên dùng redux thay vì flux

Redux js là một thư viện Javascript giúp tạo ra thành một lớp quản lý trạng thái của ứng dụng. Được dựa trên nền tảng tư tưởng của kiến trúc Flux do Facebook giới thiệu, do vậy Redux thường là bộ đôi kết hợp hoàn hảo với React (React Js và React Native). Redux cũng được đề cập đến trong bài Hướng dẫn học ReactJs, bạn nên đọc bài này trước nếu bạn muốn kết hợp Redux với Reactjs, mặc dù bạn có thể sử dụng Redux với Angular, Backbone, Ember…

Trạng thái (state) của ứng dụng là gì

Cùng lướt qua các ví dụ cho dễ:

Ví dụ 1: Để hình dung đơn giản nhất, trạng thái của ứng dụng tương tự như cái nút Lui (Back)/Tới (Forward) lịch sử của trình duyệt của trình duyệt web. Bạn mở web nhấn vào vòng vòng một hồi, rồi nhấn quay lại các trang trước, mỗi trang như vậy còn được gọi là trạng thái. Nhưng, với các ứng dụng SPA (Single Page Application) thì chuyện Lui/Tới cũng là cả vấn đề rồi.

Ví dụ 2: Không liên quan đến web nhưng rất điển hình đó là trạng thái của bàn cờ tướng hay cờ vua chẳng hạn. Mỗi khi người chơi đi một nước – trong thi đấu – họ phải ghi lại từng nước đi, bằng cách này sau khi chơi xong người ta có thể tái hiện lại bàn cờ một cách dễ dàng. Ứng với mỗi nước đi, đó chính là trạng thái của bàn cờ.

Vậy thì nó liên quan gì đến trạng thái của ứng dụng?

Một ứng dụng web hoạt động cần dữ liệu từ phía máy chủ, thao tác của người dùng,…tổng hợp các thứ này lại ta được trạng thái của ứng dụng. Nếu biết trạng thái này, có nghĩa là tại thời điểm X ta biết được máy chủ đã trả về dữ liệu gì, người dùng đã thao tác những gì, nhập vào dữ liệu gì.

Việc biết trạng thái này có quan trọng không?

Các ứng dụng web hiện nay ngày càng phức tạp, việc biết được trạng thái này giúp cho công việc kiểm soát lỗi dễ dàng hơn, nhất là nó làm cho cách chúng ta lập trình cũng đơn giản hơn. Ví dụ, nếu bạn có một biểu mẫu mua hàng, giả sử có 5 bước: xác nhận đơn hàng, áp dụng mã khuyến mãi, điền thông tin giao hàng, thanh toán, hoàn tất. Với một ứng dụng web thông thường, nếu xảy ra lỗi ở bước 4, lập trình viên sẽ kiểm tra lại và nhập dữ liệu từ 1->4, tìm lỗi sau đó sửa lỗi, công đoạn này lặp đi lặp lại n lần!!! Nếu sử dụng Redux, mỗi công đoạn xem như một trạng thái và bạn không cần phải lặp lại bước 1->4 nữa.

Các nguyên tắc cơ bản của Redux

Nguồn dữ liệu tin cậy duy nhất

Như mình đã giới thiệu cơ bản ở trên, trong quá trình hoạt động của ứng dụng, bị phụ thuộc khá nhiều yếu tố: dữ liệu từ máy chủ ban đầu, thao tác của người dùng (nhập dữ liệu, click menu, button…), dữ liệu cập nhật từ máy chủ, dữ liệu được tính toán trong ứng dụng (Ví dụ: tính toán số dư tài khoản dựa trên biến động của tỉ giá)…những yếu tố này còn gọi là nguồn dữ liệu. Những nguồn dữ liệu này đến từ những nơi khác nhau, bất kỳ khi nào, khiến cho ứng dụng của chúng ta rất khó kiểm soát, chúng tác động đến những thành phần đơn lẻ, hoặc nhiều thành phần trên ứng dụng, hoặc hiệu ứng dây chuyền. Chính vì sự phức tạp đó, là vấn đề mà Redux muốn giải quyết, tất cả các nguồn dữ liệu cần phải được quản lý và tạo thành một nguồn duy nhất, tin cậy.

Trạng thái là chỉ được phép đọc (read-only)

Trạng thái của ứng dụng không được phép thay đổi “trực tiếp”, trạng thái cũng chỉ là một đối tượng thôi mà, nên việc thay đổi là được. Tuy nhiên, với Redux hay Flux thì trạng thái chỉ thay đổi khi và chỉ khi có một sự kiện xảy ra, giống như ra trận thì chỉ được phép nghe lời từ chỉ huy, mọi tin tức tình báo đều được gởi tới chỉ huy, nếu không có lệnh từ chỉ huy thì tất cả không được phép manh động.

Thay đổi chỉ bằng hàm thuần tuý

Điều may mắn là việc sử dụng Redux js là không quá khó, việc thay đổi trạng thái của ứng dụng, được thực hiện thông qua các hàm thuần tuý. Đưa vào giá trị sự kiện, trạng thái hiện tại và hàm trả về trạng thái tiếp theo. Dù tương lai ứng dụng của bạn có thể rất lớn, nhưng các hàm reducer này thì chỉ cần nhỏ gọn thay đổi trên từng lá của cây trạng thái, và chúng hoàn toàn có thể kết hợp với nhau tạo thành chuỗi sự kiện. Ví dụ: người click vào menu (một sự kiện => thay đổi trạng thái), sau đó router cũng cần thay đổi để phù hợp với ngữ cảnh.

Tính ứng dụng của Redux js là gì

Theo mình thấy Redux có 3 ứng dụng quan trọng nhất:

  • Quản lý trạng thái: như một bản replay có thể undo/redo trạng thái của ứng dụng, phải nói là “Không thể tin được”, cá nhân mình rất thích tính tin cậy của ứng dụng mà Redux mang lại.
  • Tăng tốc phát triển: với webpack đã có Hot Module Replacement, khi kết hợp với Redux, tạo thành sự kết hợp ăn ý, bạn có thể viết code và debug rất dễ dàng, hãy quay lại ví dụ về biểu mẫu mua hàng 5 bước ở trên, nếu bạn không áp dụng Redux, đồng nghĩa bạn phải debug lặp đi lặp lại việc nhập dữ liệu, mà chưa chắc lỗi do code gây ra mà do dữ liệu nhập vào.
  • Ứng dụng offline: tất cả các thao tác của người dùng được lưu vào một cây trạng thái, khi có kết nối Internet, cây này sẽ được đồng bộ lên server bởi một loạt các sự kiện.

Sự khác biệt giữa Redux và Flux

Redux phát triển dựa trên Flux, nhưng đã lượt bỏ phần Dispatcher, và chỉ có duy nhất 1 store, …blah …blah, thôi nói nghe này: “Quên Flux đi“.
Nếu bạn chưa bao giờ nghe đến Flux hay Redux, thì đừng mất thời gian để tìm hiểu: Flux là gì, Flux khác Redux như thế nào, điểm yếu của Redux js là gì? Mình cũng đã từng mất thời gian như vậy, nhưng bây giờ mình tin chỉ cần nghiên cứu Redux là đủ. Đây là các lý do để chỉ nghiên cứu “Redux js là gì“:

  • Hiện tại Redux đã đạt ~20k stars Github khi chưa đầy 1 năm
  • Ứng dụng F8 của Facebook không sử dụng Flux mà sử dụng Redux:
  • Dan Abramov, người tạo ra Redux đã gia nhập Facebook từ tháng 11/2015

Kết

Mình hi vọng qua bài “Redux js là gì” này, mình đã truyền tình yêu của mình dành cho Redux đến bạn. Cái hay của Redux là nó không phụ thuộc vào việc bạn sử dụng framework nào, nó là kiến trúc giúp cho ứng dụng phát triển nhanh, đáng tin cậy, và dễ hiểu khi làm việc nhóm. Cách người ta ghi lại nước cờ, làm cho tất cả mọi người đều dễ dàng hiểu và trình bày lại bàn cờ ra sao, thì Redux cũng như vậy!

Series Navigation

Nói chung Redux khá là phổ biến. Tuy nhiên, không phải tất cả chúng ta đều biết nó là gì và cách sử dụng nó ra sao. Trong bài này, chúng ta sẽ xem vài lý do tại sao nên sử dụng redux bằng cách phân tích những lợi ích mà nó mang lại và cách hoạt động của nó.

Redux là một predictable state management tool cho các ứng dụng Javascript. Nó giúp bạn viết các ứng dụng hoạt động một cách nhất quán, chạy trong các môi trường khác nhau (client, server, and native) và dễ dàng để test. Redux ra đời lấy cảm hứng từ tư tưởng của ngôn ngữ Elm và kiến trúc Flux của Facebook. Do vậy Redux thường dùng kết hợp với React.

Tại sao nên dùng redux thay vì flux

Do yêu cầu cho các ứng dụng single-page sử dụng Javascript ngày càng trở lên phức tạp thì code của chúng ta phải quản lý nhiều state hơn.

State có thể bao gồm là data trả về từ phía Server và được cached lại hay như dữ liệu được tạo ra và thao tác ở phía client mà chưa được đẩy lên phía server. UI state cũng trở lên phức tạp vì chúng ta cần quản lý việc active Routes, selected tabs, spinners, điều khiển phân trang …vv.

Với Redux, state của ứng dụng được giữ trong một nơi gọi là store và mỗi componentđều có thể access bất kỳ state nào mà chúng muốn từ chúng store này.

Hầu hết các lib như React, Angular, etc được built theo một cách sao cho các components đến việc quản lý nội bộ các state của chúng mà không cần bất kỳ một thư viện or tool nào từ bên ngoài.

Nó sẽ hoạt động tốt với các ứng dụng có ít components nhưng khi ứng dụng trở lên lớn hơn thì việc quản lý states được chia sẻ qua các components sẽ biến thành các công việc lặt nhặt.

Trong một app nơi data được chia sẻ thông qua các components, rất dễ nhầm lẫn để chúng ta có thể thực sự biết nơi mà một state đang live. Một sự lý tưởng là data trong một component nên live trong chỉ một component. Vì vậy việc share data thông qua các components anh em sẽ trở nên khó khăn hơn.

Ví dụ, trong react để share data thông qua các components anh em, một state phải live trong component cha. Một method để update chính state này sẽ được cung cấp bởi chính component cha này và pass như props đến các components con.

Đây là một ví dụ:

class App extends React.Component { constructor(props) { super(props); this.state = { userStatus: "NOT LOGGED IN"} this.setStatus = this.setStatus.bind(this); } setStatus(username, password) { const newUsers = users; newUsers.map(user => { if (user.username == username && user.password === password) { this.setState({ userStatus: "LOGGED IN" }) } }); } render() { return (
); } });

Giờ chúng ta hãy tưởng tượng rằng nếu một state phải được chia sẻ giữa các component cách khá xa nhau trong một tree components và state này phải được passed từ một component đến một component khác cho đến khi nó đến được nơi mà nó được gọi.

Cơ bản là, state mà chúng ta đang nói đến phải được nhấc lên một component cha gần nhất và tiếp nữa cho đến khi nó đến được cái component tổ tiên chứa tất cả các components nó cần cái state này sau đó pass cái state này xuống @@. Điều này sẽ khiến state trở nên khó hơn trong việc maintain và less predictable.

Điều này khiến cho bộ phận quản lý state trong app trở lên bừa bộn cũng như app trở lên vô cùng phức tạp. Đó là lý do tại sao chúng ta cần một state management tool như Redux.

Tại sao nên dùng redux thay vì flux

Cái cách mà Redux hoạt động là khá đơn giản. Nó có 1 store lưu trữ toàn bộ state của app. Mỗi component có thể access trực tiếp đến state được lưu trữ thay vì phải send drop down props từ component này đến component khác.

Có 3 thành phần của Redux: Actions, Store, Reducers.

Actions đơn giản là các events. Chúng là cách mà chúng ta send data từ app đến Redux store. Những data này có thể là từ sự tương tác của user vs app, API calls hoặc cũng có thể là từ form submission.

Actions được gửi bằng cách sử dụng store.dispatch() method, chúng phải có một type property để biểu lộ loại action để thực hiện. Chúng cũng phải có một payload chứa thông tin. Actions được tạo thông qua một action creator. Ví dụ:

const setLoginStatus = (name, password) => { return { type: "LOGIN", payload: { username: "foo", password: "bar" } } }

Reducers là các function nguyên thủy chúng lấy state hiện tại của app, thực hiện một action và trả về một state mới. Những states này được lưu như những objects và chúng định rõ cách state của một ứng dụng thay đổi trong việc phản hồi một action được gửi đến store.

  Authorization với JWT trong React + Redux App

  Vẽ biểu đồ thống kê trong React JS sử dụng Highcharts

  Một vài khái niệm nâng cao trong React.js

Đây là một ví dụ về cách mà Reducers hoạt động trong Redux:

const LoginComponent = (state = initialState, action) => { switch (action.type) { case "LOGIN": return state.map(user => { if (user.username !== action.username) { return user; } if (user.password == action.password) { return { ...user, login_status: "LOGGED IN" } } }); default: return state; } };

Store lưu trạng thái ứng dụng và nó là duy nhất trong bất kỳ một ứng dụng Redux nào. Bạn có thể access các state được lưu, update state, và đăng ký or hủy đăng ký các listeners thông qua helper methods.

Tạo một store cho một login app:

const store = createStore(LoginComponent);

Các actions thực hiện trên một state luôn luôn trả về một state mới. Vì vậy, state này là đơn giản và dễ đoán.

Bây giờ, chúng ta đã biết hơn một chúng về Redux, hãy trở lại với ví dụ Login component và xem cách cách mà Redux có thể giúp chúng ta được gì.

class App extends React.Component { render() { return (
) } }

Bạn có thể xem video Redux cơ bản của Giảng viên Nguyễn Đức Hoàng tại đây.

Ở phạm vi bài này mình đã trình bày nguyên lý cơ bản và cách thức hoạt động của Redux là gì rồi. Để các bạn có thể nắm được cũng như hình dung nó sinh ra để làm việc gì, bài viết mới thể hiện được các tình huống đơn giản nhất thông qua ví dụ đơn giản.

Còn trong khi làm dự án thực tế công việc chủ yếu là tương tác với server (fetch data) và xử lý data sau đó, thì đó là về bất đồng bộ asynchronous và xử lý side-effect sau mỗi action được gọi.

Việc làm Reactjs giờ lương toàn nghìn đô không. Anh em vào tham khảo thêm.

Tài liệu tham khảo: blog.logrocket.com

Có thể bạn muốn xem thêm:

Xem thêm việc làm Redux tại TopDev