+2

React context API (Part 1) — Passing state to child components made easy

Trong docs của ReactJS có câu thế này

React has a powerful composition model, and we recommend using
composition instead of inheritance to reuse code between components.

Có thể hiểu là họ khuyến khích người dùng react nên sử dụng composition hơn là inheritance để tái sử dụng lại những đoạn code biến chúng thành các components 😃.

Có một vài cách sau đây để tạo ra các components có thể reuse

  • Wrapper component
  • this.props.children
  • Children function
  • HOC (higher order component)
  • Context

Không lòng vòng, nay ta tìm hiểu về Context trước :3

1. What is context?

React context API được xây dựng để giúp việc truyền dữ liệu đến các components dễ dàng hơn.

Có khá nhiều tool làm việc này dễ dàng, điên hình như Redux hiện rất được ưa chuộng - khá nhiều sao á ✌️

Thế ngắn gọn context là gì? Context cho phép dữ liệu trạng thái được truyền từ parent component sang child component thông qua Provider. Mỗi child component sẽ có Consumer sẽ tác động đến các thay đổi state từ parent component. Bây giờ, một func child component có thể tác động đến state của parent component.

2. Why is context useful?

Context cho phép dữ liệu được chia sẻ như một global data trong một component. Điều này làm cho code của chúng ta dễ đọc hơn. Một child component sẽ tác động trực tiếp vào component state trên cùng bất kể child component nằm ở đâu trong component đó.

3. Simple Tutorial

Đầu tiên hãy tạo 1 file Context.js. Sẽ có sẵn 2 component cho ta sử dụng ProviderConsumer

import { createContext } from "react"
const { Provider, Consumer } = createContext()
export { Provider, Consumer }

import createContext từ react trước nhé. Sau đó là tạo ProviderConsumer, Provide sẽ cung cấp state đến Consumer, Mỗi Consumer sẽ tác động đến những lần thay đổi của Provider

Tiếp, ta phải tạo parent component

import React, { Component } from "react"
import { Provider } from "./Context"
import Child from "./Child"
class Parent extends Component {
  state = {
    people: [
      { id: 0, name: "Bob", age: 24 },
      { id: 1, name: "Jack", age: 22 },
      { id: 2, name: "Jill", age: 26 },
    ],
  }
  render() {
    return (
      <Provider value={this.state}>
        <Child />
      </Provider>
    )
  }
}
export default Parent

Lúc này Provider context đang wrap child component. value được set là {this.state}. Vậy trong Child component sẽ là 1 Consumer và sẽ tác động đến value được cung cấp bởi Provider. Và trong TH này value = state.

Note: nó sẽ không work nếu các components không được bao bởi 1 Provider :))

import Child component mà chưa tạo file thì được nhiên sẽ lỗi nhỉ, tạo thôi :3

import React from "react"
import { Consumer } from "./Context"
import Grandchild from "./GrandChild"
function Child() {
  return (
    <Consumer>
      {context => (
        <div>
          <h1>Child Component</h1>
          {context.people.map(person => {
            return (
              <p key={person.id}>
                Hi, I am {person.name} and I am {person.age}
                years old.
              </p>
            )
          })}
          <GrandChild />
        </div>
      )}
    </Consumer>
  )
}
export default Child

Tóm tắt lại các bước thì, đầu tiên Consumer context đã đc import, sau đó thì toàn bộ components đã được bao bởi Consumer

<Consumer>
  {context => (
    <div>
      <h1>Child Component</h1>
      {context.people.map(person => {
        return (
          <p key={person.id}>
            Hi, I am {person.name} and I am {person.age} years old.
          </p>
        )
      })}
      <GrandChild />
    </div>
  )}
</Consumer>

Bên trong Consumer ta khai báo {context => ( ... )}. context ở đây chỉ là 1 tên tùy ý - có thể chọn tên khác được

Tập trung vào đoạn này để phân tích rõ hơn

{
  context.people.map(person => {
    return (
      <p key={person.id}>
        Hi, I am {person.name} and I am {person.age} years old.
      </p>
    )
  })
}

Vì ở đây context đã được truyền đến Consumer và tạo kết nối đến state của parent component (hiểu đơn giản là có thể access các value từ provider), cho nên ta có thể sử dụng được people. Và việc còn lại hiển giờ là show các giá trị của people ra

Giờ ta thử thay đổi value mà Provider cung cấp xem sao nhé

<Provider value={state: this.state}>
  <Child />
</Provider>

Một cách khác để ta có thể truyền thêm nhiều params cho Consumer sử dụng.

Và đây là cách gọi chúng ra:

{
  context.state.people.map(person => {    return (
      <p key={person.id}>
        Hi, I am {person.name} and I am {person.age} years old.
      </p>
    )
  })
}

Và giờ ta sẽ đến phần của cháu nội :v - tác giả vui tính ghê :v

import React from "react"
import { Consumer } from "./Context"
function GrandChild() {
  return (
    <Consumer>
      {context => (
        <div>
          <h1>Grandchild Component</h1>
          {context.people.map(person => {
            return (
              <p key={person.id}>
                Hi, I am {person.name} and I am {person.age} years old                                             
              </p> 
            )
          })}
        </div>
      )}
    </Consumer>
  )
}
export default GrandChild

Xem lại cấu trúc thì là như thế này Provider > Child > GrandChild. Vậy nghĩa là GrandChild component có quyền truy cập để get value được nhận từ Provider

Child component là component đầu tiên nhận state từ context provider. Sau đó, nó đi trước để chuyển state cho Grandchild. Như vậy, ngay cả thành phần Grandchild được bao bọc trong Child component cũng có quyền truy cập vào parent state

Conclusion

Với một tutorial nhỏ ta lắm được nguyên tắc nhỏ: State from parent component sẽ được truyền child components thông qua Provider. Consumer dùng được sử dụng trong các child componens để cho phép access các giá trị được truyền trong Provider.

Tham khảo: https://reactjs.org/docs/context.html

Bài viết được dịch từ nguồn: https://medium.com/javascript-in-plain-english/react-context-api-part-1-passing-state-to-child-components-made-easy-5152001e1988

Hy vọng giúp được các b mới học ReactJS :bowman


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.