ReactJS: Tìm hiểu khái niệm Context (Phần 1)

ReactJS: Tìm hiểu khái niệm Context (Phần 1) 1

Trong ứng dụng React, data thường truyền từ trên xuống dưới thông qua props. Nhưng cách này sẽ trở nên phức tạp đối với các loại dữ liệu global như locale, theme…, chúng ta phải truyền chúng qua nhiều lớp component để sử dụng. Context lúc này như vị cứu tinh của React: cung cấp một cách chia sẻ dữ liệu giữa các component như một biến global mà không cần phải truyền props qua mỗi cấp component.

Bạn có cần sử dụng Context hay không?

Khi nào cần sử dụng Context?

Thông thường, chúng ta sử dụng 2 khái niệm “top-down-data-flow” và “Lifting state up” để truyền dữ liệu từ component cha đến con và cập nhật dữ liệu từ component con lên cha.

Giả sử chúng ta có 3 component A, B, C và lần lượt là con của nhau:

Cách quản lý state thông thường qua các tầng component

Nếu số lượng component lên đến hàng chục, chúng ta sẽ thấy việc truyền props như thế này sẽ trở nên dài dòng, dư code và khó quản lý. Ngay cả khi những component con trung gian không sử dụng đến props, nó cũng phải nhận props từ component cha để chuyển xuống component con của nó khi cần.

Đó là lý do mà React Context ra đời để giải quyết vấn đề nhập nhằng này!

Ý tưởng của Context là: tập trung lưu dữ liệu (props) ở một nơi. Sau đó React sẽ cung cấp các API để các component có thể lấy props đó trực tiếp mà không cần qua các component trung gian.

Quản lý state với React Context

Context được thiết kế để chia sẻ dữ liệu như một biến global cho một cây component. Ví dụ các giá trị như authenticated user (thông tin người dùng lúc đăng nhập), theme, languages… được sử dụng thường xuyên ở các tầng React component.

Khi bắt đầu với một dự án dù lớn hay nhỏ, chúng ta nên sử dụng Context từ ban đầu. Sau này có lẽ dự án sẽ phát triển lớn hơn, nhiều component hơn, lúc đó việc truyền props qua từng component sẽ rất phiền phức.

Ưu – nhược điểm của Context

So với luồng quản lý thông thường, Context có những ưu – nhược điểm nhất định.

Ưu điểm

Nhược điểm

Cách sử dụng Context (Context API)

React cung cấp các Context API để tạo Context, lấy giá trị của Context cho các loại component:

React.createContext

API này cho phép khởi tạo một đối tượng Context.

// defaultValue là giá trị được khởi tạo mặc định lúc đầu của MyContext
const MyContext = React.createContext('defaultValue');

Dưới đây là đối tượng Context được khởi tạo, với các thuộc tính Provider, Consumer đi kèm như một component:

Giá trị của đối tượng Context được khởi tạo

Giá trị defaultValue này được sử dụng khi một component không được bọc bởi component Context.Provider. Nó hữu ích cho việc kiểm thử component độc lập mà không cần phải bọc chúng lại.

Context.Provider

Mỗi đối tượng Context đều đi cùng với một Provider như một React component.

<MyContext.Provider value={/* some value */}>{children}</MyContext.Provider>

Component <Provider> nhận một props là “value” để truyền đến component con (có thể được bọc bởi <Consumer> hoặc không). Giá trị của props này không phụ thuộc vào phương thức shouldComponentUpdate của lifecycle updating.

Đối tượng Provider của Context

Một component <Provider> có thể chứa nhiều component <Provider> và <Consumer> lồng nhau.

Class.contextType

Thuộc tính contextType được sử dụng cho các class component. Thuộc tính này được gán vào đối tượng Context khai báo bằng React.createContext().

Ta lấy giá trị props “value” của component <Provider> thông qua cú pháp this.context, ta có thể sử dụng nó trong mọi phương thức của lifecycle:

class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* ... */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* ... */
  }
}
MyClass.contextType = MyContext;

Ngoài ra, chúng ta cũng có thể sử dụng từ khóa static để sử dụng contextType bên trong class component:

const MyContext = React.createContext('defaultValue');

class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    <h1 className={value}>Wiki Tino</h1>
  }
}

this.context chỉ trỏ tới một context duy nhất. Giá trị mặc định của nó là đối số “defaultValue” khi khởi tạo Context.

Nếu muốn sử dụng nhiều context khác, chúng ta phải sử dụng “Consuming Multiple Context”.

Context.Consumer

Để lấy giá trị props “value” của component <Provider> trong một function component, ta dùng component Consumer.

Function component nhận giá trị “value” của <Provider> gần nhất trong các tầng component và trả về React element.

const FunctionComponent = (props) => (
  <MyContext.Consumer>
    {(val) => <span className={val}>Function Component</span>}
  </MyContext.Consumer>
);
Đối tượng Consumer của Context

Nếu MyContext này không có Provider thì tham số val sẽ là đối số defaultValue truyền vào createContext().

Context.displayName

Sau khi một Context được khởi tạo bởi createContext(), nó nhận một thuộc tính displayName kiểu string (chuỗi).

React DevTools sẽ sử dụng chuỗi này để hiển thị lại tên Context. Điều này hữu ích cho việc debug.

const MyContext = React.createContext(/* vài giá trị */);
MyContext.displayName = 'MyDisplayName';

<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
Tên context đươcj hiển thị bằng giá trị displayName

Tổng kết

Chúng ta đã đi tìm hiểu xong khái niệm và các API liên quan đến React Context. Bài viết sau chúng ta sẽ đi vào ví dụ thực tế sử dụng React Context như thế nào nhé !

Cám ơn các bạn đã ghé thăm bài viết này!

Xem bài viết sau tại: ReactJS: Tìm hiểu khái niệm Context (Phần 2)

CÔNG TY CỔ PHẦN TẬP ĐOÀN TINO

Exit mobile version