Kiến trúc Redux

Redux là thư viện hoạt động như một thùng chứa các state và giúp quản lý luồng dữ liệu ứng dụng. Nó được giới thiệu trở lại vào năm 2005 tại hội nghị ReactEurope. Nó tương tự như Flux và có cùng nhiều điểm chung

Giống như kiến trúc Flux, chúng ta có một component view (của React) gửi một Action. Action tương tự cũng có thể được gửi từ phần khác của hệ thống. Action này được gửi không phải đến trung tâm mà trực tiếp đến một Store. Đây chính là điểm khác biệt lớn nhất giữa Redux và Flux. Logic quyết định dữ liệu được thay đổi trực tiếp như thế nào trong các hàm được gọi là Reducers. Khi Store nhận được một Action nó sẽ yêu cầu Reducers thông tin mới nhất của State được cập nhập bằng cách gửi state hiện tại và thông tin Action. Sau đó Reducers cần trả về State mới với định dạng là Immutable.  Sau đó Store sẽ tiếp tục và thực hiện cập nhập State nội bộ của nó. Và bước cuối cùng, React Component sẽ thực hiện render lại

Khái niệm này là khá tuyến tính và tuân theo luồng dữ liệu một hướng.

Actions

Biểu tượng Actions trong Redux chỉ là một object với một thuộc tính type. Ngoài ra các thông tin khác trong object đó được coi như là dữ liệu cụ thể theo ngữ cảnh và nó không liên quan đến pattern mà liên quan đến logic ứng dụng. Ví dụ

const CHANGE_VISIBILITY = 'CHANGE_VISIBILITY';
const action = {
  type: CHANGE_VISIBILITY,
  visible: false
}

Theo kinh nghiệm thì chúng ta nên đặt một hằng số định nghĩa như ở trên CHANGE_VISIBILITY cho type của Actions và có thể sử dụng ở cả 2 bên Reducers và Actions.

Thuộc tính visible là dữ liệu meta mà chúng ta đã nói ở bên trên. Redux sẽ không làm gì xử lý đến nó. Nghĩa là nó sẽ được sử dụng theo bối cảnh của ứng dụng.

Mỗi khi chúng ta muốn gửi một phương thức chúng ta phải sử dụng các object như vậy. Tuy nhiên nó cũng tạo phiền phức khi chúng ta phải viết đi viết lại như vậy. Đấy là lý do tại sao có khái niệm Action Creators. Một Action Creator là một hàm trả về một object và có thể có hoặc không có tham số liên quan trực tiếp đến các thuộc tính Action. Ví dụ như chúng ta có Action Creator cho cho Action ở trên như sau

const changeVisibility = visible => ({
  type: CHANGE_VISIBILITY,
  visible
});

changeVisibility(false);
// { type: CHANGE_VISIBILITY, visible: false }

Chú ý rằng chúng ta truyền giá trị của visible như một tham số mà chúng ta không phải nhớ chính xác kiểu của Action. Sử dụng các trợ giúp như trên giúp cho code của chúng ta gọn nhẹ và dễ đọc

Store

Redux cung cấp một phương thức createStore để tạo một Store.

import { createStore } from 'redux';

createStore([reducer], [initial state], [enhancer]);

Như chúng ta đã biết, Reducer là một hàm nhận State hiện tại và Action sau đó trả về một State mới.  Tham số thứ 2 là State ban đầu của Store. Đây là công cụ hữu ích để khởi tạo ứng dụng với dữ liệu mà chúng ta có. Đặc tính này về bản chất xử lý giống SSR (server side render) hoặc persistent. Tham số thứ 3, enhancer, cung cấp một API cho ứng dụng mở rộng Redux với middlewares bên thứ 3 và về cơ bản là thêm một số chức năng mà không hỗ trợ. Ví dụ như một công cụ xử lý bất đồng bộ.

Sau khi tạo Store có 4 phương thức: getStatedispatchsubscribe và replaceReducer. Có lẽ phương thức quan trọng nhất là dispatch

store.dispatch(changeVisibility(false));

Đây là chỗ chúng ta sử dụng Action Creator. Chúng ta truyền kết quả của chúng hoặc trong thế giới các object Action khác đến phương thức dispatch này. Sau đó nó được truyền đến Reducers của ứng dụng.

Trong ứng dụng React điển hình, chúng ta thường không sử dụng getState và subscribe trực tiếp bởi vì có một trợ giúp khác giúp chúng ta kết nối các component với Store và subscribe hiệu quả cho các thay đổi. Như một phần của subscribe chúng ta cũng có thể nhận được các State hiện tại nên không phải gọi hàm getStatereplaceReducer là một dạng nâng cao của API dùng để hoán đổi Reducer hiện tại được sử dụng bởi Store. Nhưng trong thực tế tôi cũng chưa bao giờ sử dụng phương thức này

Reducer

Hàm Reducer có lẽ là phần đẹp nhất của Redux. Ngoài ra trước đây trong tâm trí tôi thường viết các pure function sử dụng immutable nhưng Redux bắt buộc chúng ta phải thực hiện điều đó. Có 2 đặc điểm của Reducer hơi quan trọng và nếu thiếu chúng pattern sẽ bị hỏng

  • 1 – Trước hết các hàm phải là pure function – Nghĩa là hàm phải trả về cùng một kết quả với đầu vào là như nhau
  • 2 – Nó nên là no side effect – không sử dụng các biến Global, sử dụng gọi bất đồng bộ hoặc phải đợi sử dụng promise để nhận kết quả trả về

Đây là một Reducer đơn giản

const counterReducer = function (state, action) {
  if (action.type === ADD) {
    return { value: state.value + 1 };
  } else if (action.type === SUBTRACT) {
    return { value: state.value - 1 };
  }
  return { value: 0 };
};

Nó là no side effect và luôn luôn trả về một object mới hoàn tất mỗi lần. Chúng ta lưu trữ giá trị mới dựa trên State trước đấy  và kiểu Action đến

Tạo React Component

Nếu chúng ta nói về Redux sử dụng trong React, chúng ta hầu hết muốn nói về react-redux module. Nó cung cấp 2 thứ để giúp kết nối Redux với các component.

  1. Component – Nó là một component nhận Store và luôn sẵn sàng được sử dụng cho các component con bên dưới thông qua API context của React.
<Provider store={ myStore }>
  <MyApp />
</Provider>

Chúng ta thường sử dụng ở một nơi duy nhất

2. Hàm connect – Nó là hàm dùng để đăng ký các thay đổi trong Store và render lại component. Nó được thực thi sử dụng higher order component.

connect(
  [mapStateToProps],
  [mapDispatchToProps],
  [mergeProps],
  [options]
)

Tham số mapStateToProps là một hàm nhận tham số là state hiện tại và phải trả về một object theo định dạng key-value mà đang nhận được như props cho component của React

const mapStateToProps = state => ({
  visible: state.visible
});

mapDispatchToProps giống như tham số đầu tiên nhưng thay thế State nhận hàm dispatch. Đây là chỗ chúng ta định nghĩa một props cho các Action đưa ra.

const mapDispatchToProps = dispatch => ({
  changeVisibility: value => dispatch(changeVisibility(value))
});

mergeProps kết hợp cả mapStateToProps và mapDispatchToProps và props gửi đến component, giúp chúng ta lưu trữ props tốt hơn.Ví dụ chúng ta có thể đưa ra 2 Action, chúng ta có thể kết hợp chúng thành props duy nhất và gửi đến React. options nhận 2 cài đặt và giúp kiểm soát các kết nối hoạt động như thế nào.

 

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

Your email address will not be published.