Redux là gì?
Redux là một thư viện JavaScript giúp quản lý trạng thái (state) trong ứng dụng
Để hiểu rõ về khái niệm ta nên đi qua lịch sử của nó.
Lịch sử Redux
Vào năm 2003 Facebook giới thiệu ReactJS tới cộng đồng công nghệ, thế nhưng ReactJS chỉ là thư viện tạo các Component nhưng lại không có khả năng quản lý state (trạng thái) trong ứng dụng. Vậy nên Flux đã được tạo ra để giúp quản lý state.
Tuy nhiên, Dan Abramov khi đang nghiên cứu về Flux của Facebook và ngôn ngữ ELM đã tạo ra một thư viện mới có tên là Redux để giảm bớt sự phức tạp của Flux dựa trên cấu trúc ELM.
Redux là gì?
Nói một cách đơn giản, Redux là một công cụ quản lý trạng thái. Mặc dù nó được sử dụng chủ yếu với React, nhưng nó có thể được sử dụng với bất kỳ khung hoặc thư viện JavaScript nào khác.
Nó rất nhẹ ở mức 2KB (bao gồm cả phụ thuộc), vì vậy bạn không phải lo lắng về việc nó làm cho ứng dụng của bạn có kích thước lớn.
Với Redux, trạng thái ứng dụng (state) của bạn được giữ trong một "store" và mỗi thành phần có thể truy cập bất kỳ trạng thái nào mà nó cần từ "store"này. Sâu hơn một chút để xem tại sao bạn có thể cần một công cụ quản lý trạng thái.
Chú ý: ReduxJS là một thư viện Javascript khác với Redux Framework là một WordPress Framework.
Tại sao phải sử dụng Redux?
Như nói ở trên thì việc chia sẻ State giữa các Component với nhau theo cách của React là khá phức tạp và rắc rối, vậy nên Redux sẽ giải quyết một bài toán khó trong lập trình React đó là chia sẻ state.
Ví dụ như khi chúng ta muốn truyền dữ liệu từ component A sang component D thì bắt buộc phải thông qua component B,C.
Như hình bên trên khi chúng ta cần chia sẻ dữ liệu giữa các component với nhau bằng cách sử dụng props thì bắt bụôc phải thông qua các component trung gian. Điều này khá phức tạp và dễ gây nhầm lẫn.
Vậy nên, để có thể truyền dữ liệu một cách tối ưu và đơn giản hơn Redux sẽ lưu dữ liệu vào một store, từ đó cấp phát dữ liệu cho các component cần thiết.
Lúc này store sẽ đóng vai trò trung gian, nó có nhiệm vụ chứa và phân phát dữ liệu. Cùng xem hình minh hoạ bên dưới.
Giả sử bạn muốn chia sẽ dữ liệu từ component A tới component D thì chỉ cần đẩy state vào Store và Store sẽ cấp phát dữ liệu cho component D thay vì đi trung qua các component khác.
Đây là mô hình mà Redux sử dụng, qua đó việc kiểm soát dữ liệu sẽ dễ dàng và tối ưu hơn.
Cấu trúc của React
Về cơ bản Redux có 4 thành phần như sau:
1. Action
Action đơn giản là các events (sự kiện). Chúng là cách mà chúng ta gửi dữ liệu từ ứng dụng đến Store của Redux. Những dữ liệu này có thể là từ sự tương tác của người dùng, các lệnh gọi API hoặc cũng có thể là từ form được submit.
Các Action được gửi bằng phương thức store.dispatch() và 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"
}
}
}
2. Reducers
Reducers là các hàm thuần túy lấy trạng thái hiện tại của ứng dụng, thực hiện một hành động và trả về trạng thái mới. Reducer có nhiệm vụ xử lý các hành động được gửi đến.
Các trạng thái này được lưu trữ dưới dạng đối tượng và chúng xác định trạng thái của ứng dụng thay đổi như thế nào để đáp ứng với hành động được gửi đến "store".
Nó dựa trên hàm "reduce" trong JavaScript, trong đó một giá trị được tính từ nhiều giá trị sau khi thực hiện chức năng gọi lại.
Ví dụ:
const LoginComponent = (state = initialState, action) => {
switch (action.type) {
// This reducer handles any action with type "LOGIN"
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;
}
};
3. Store
Store lưu trạng thái (state) của ứ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 qua getState()
, update state qua dispatch(action)
, và đăng ký or hủy đăng ký các listeners thông qua helper methods.
Ví dụ, tạo một store cho ứng dụng login:
const store = createStore(LoginComponent);
Các Action thực hiện trên một state luôn luôn trả về một state mới. Bởi vậy, state này là đơn giản và dễ đoán được.
Ví dụ: trong 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 (
<div>
<Status user={this.props.user.name}/>
<Login login={this.props.setLoginStatus}/>
</div>
)
}
}
4. View
View là để hiển thị dữ liệu được cung cấp bởi Store
Redux hoạt động như nào?
Redux có 1 Store lưu trữ toàn bộ state của ứng dụng. Mỗi component có thể access trực tiếp đến state được lưu trữ trong Store thay vì phải thông qua các component khác.
Chúng ta sẽ khó mà hiểu hết được các hoạt động của Redux nếu chỉ nhìn vào 4 thành phần cơ bản trên. Chúng ta sẽ tìm hiểu kĩ hơn thông qua các hình tượng minh họa sau.
Store trong Redux, nó có nhiệm vụ lưu trữ và phân phát dữ liệu cho các component. Trong store bao gồm các thành phần như dispatcher (có nhiệm vụ kích hoạt các action bên trong reducer), reducer có nhiệm vụ xử lý các hành động được gửi đến.
Sau khi một action được thực thi, dispathcer sẽ được kích hoạt và gửi đến reducer một action đó. Lúc này reducer thực hiện hành động dựa vào action được gửi đến.
Sau đó, đồng thời reducer lưu lại giá trị của state mới vào trong store.
Ví dụ, ở đây mình có 1 đoạn code thực hiện tăng giảm giá trị của state thông qua Redux.
import redux from 'redux';
//Reducer
const counter = (state = 0, action) => {
//Kiểm tra điều kiện
switch (action.type) {
case 'INCREMENT':
return state + 1;
}
return state;
};
//Đây là store
const store = redux.createStore(counter);
//Thực hiện dispath
store.dispath({type : 'INCREMENT'})
Ở ví dụ trên khi dispath được thực thi thì lúc này nó sẽ gửi đến cho reducer một action có type là INCREMENT, reducer kiểm tra action và tiến hành tăng giá trị của state và trả về state mới cho store.
Lợi ích khi sử dụng Redux trong React?
+ Dễ theo dõi: Các state không nhất thiết phải được nâng cấp, việc này sẽ giúp người dùng dễ dàng theo dõi sự thay đổi của các action.
+ Dễ bảo trì: Các phần tử sẽ không dùng bất kỳ cá state hay phương thức nào để cho các phần tử con được quyền chia sẻ dữ liệu giữa chúng. Như vậy ứng dụng sẽ được đơn giản hóa và dễ dàng bảo trì hơn.
+ Redux hỗ trợ dự đoán trạng thái của state: Redux là phần mềm hỗ trợ dự đoán và quản lý, nếu như cả state và action được chuyển về reducers thì sẽ có cùng một kết quả vì reducer là hàm thuần túy. State sẽ luôn ở một trạng thái và sẽ không bao giờ thay đổi.
+ Redux có tính khả năng bảo trì: Redux có hệ thống code cực kỳ nghiêm ngặt, đối với những người đã sử dụng và hiểu về Redux thì sẽ tiếp cận dễ dàng hơn. Nhưng chính việc này giúp cho Redux có thể được bảo trì dễ dàng hơn.
+ Redux cho phép người dùng gỡ lỗi một cách dễ dàng bằng cách lưu lại những action và state để nhận diện những trường hợp lỗi mã hóa, lỗi mạng và các lỗi khác khi định dạng trong quá trình thực hiện chương trình. Việc gỡ lỗi thông thường sẽ mất rất nhiều thời gian và phức tạp nhưng Redux đã sản xuất ra Redux DevTools để hỗ người dùng thực hiện thao tác gỡ lỗi dễ dàng hơn.
+ Redux có hiệu suất tốt: Redux thực hiện nhiều tối ưu hóa hiệu suất bên trong để thành phần được kết nối của riêng bạn và chỉ hiển thị khi nó thực sự cần.
+ Redux cho phép người dễ dàng kiểm tra dùng kiểm tra Reducer trong Redux.
+ Tính năng bền bỉ của Redux giúp người dùng có thể giữ các state trong ứng dụng trong bộ nhớ cục bộ và khôi phục khi refresh.
+ Hiển thị từ máy chủ Trên máy chủ cũng có thể để Redux được hiển thị, người dùng có thể xử lý các kết xuất ban đầu của chương trình bằng cách truyền tải những state đến các server máy chủ và đợi phản hồi từ nó. Các thành phần bắt buộc sau đó sẽ được hiển thị trong HTML và được gửi đến các máy khách
Một vài khái niệm khác liên quan đến Redux
Redux Thunk là gì?
Khi nhắc đến Redux thì không thể không nhớ đến Redux Thunk. Và định nghĩa này đã được các chuyên gia nhận định như sau:
Redux Thunk là một Middleware có thể cho phép người dùng viết các Action trả về một function. Thay vì phải sử dụng một plain javascript object bằng cách trì hoãn quá trình đưa action đến reducer.
Ngoài ra, Redux Thunk còn được sử dụng nhằm mục đích xử lý các logic bất đồng bộ phức tạp. Những đồng bộ này cần truy cập đến store hoặc lấy dữ liệu như Ajax request.
Redux Persist là gì?
Redux Persist là dạng gói tự động hóa cho quy trình duy trì trạng thái từ cửa hàng Redux của bạn đến với bộ nhớ của thiết bị cục bộ.
Ví dụ như:
Redux Persist có nhiệm vụ thực hiện tái tạo cửa hàng Redux trong các lần khởi chạy ứng dụng. Các tiện ích này sẽ giúp người dùng giảm thiểu công việc cũng như quá trình để duy trì được dữ liệu trên thiết bị. Có thể là mã thông báo xác thực hoặc các cài đặt tài khoản.
Việc sử dụng Redux Persist sẽ giúp bạn thực hiện công việc hoàn toàn tự động mà chỉ cần lượng nhỏ bản ghi sẵn cho quá trình khởi tạo. Gói tự động này hoạt động rất hiệu quả và sở hữu nhiều bộ giảm được thiết kế vô cùng tốt. Ngoài ra, nó còn có thể giúp cho các bộ giảm bớt chi tiết khi cần thiết hoặc khi ứng dụng đang ngày càng phức tạp. Nhờ vậy mà quy trình quản lý cửa hàng Redux sẽ trở nên đơn giản mà hiệu quả hơn.