Context

Giả sử ta có component sau:

function Food({ title: name, children }) {
  const [isActive, setIsActive] = useState(false)
  return (
    <section>
      <h3>{name}</h3>
      {isActive ? <p>{children}</p> : <button onClick={() => setIsActive(true)}>Show</button>}
    </section>
  )
}

Có thể thấy, khi người dùng click vào nút “Show” thì component sẽ hiển thị ra nội dung của children.

Ta sử dụng hai component Food ở trong một parent component có tên là Menu như sau:

function Menu() {
  return (
    <>
      <Food name="Apple">🍎</Food>
      <Food name="Grape">🍇</Food>
    </>
  )
}

Việc bấm vào một nút “Show” của một component Food sẽ không làm ảnh hưởng đến state của component Food còn lại:

Question

Làm cách nào để khi ta bấm “Show” một component thì (các) component còn lại sẽ bị ẩn đi?

Lifting State up

Để làm được điều đó, ta cần phải đem việc quản lý state từ child component (Food) lên parent component (Menu). Đây gọi là kỹ thuật lifting state.

Trước tiên, ta cần tạo ra một state cho phép lưu giữ index của loại trái cây đang được hiển thị ở parent component:

const [activeIndex, setActiveIndex] = useState(0)

Sau đó, truyền props isActive có giá trị được tính toán dựa trên activeIndex và các event handler vào các child component.

<>
  <Food name="Apple" isActive={activeIndex === 0} onShow={() => setActiveIndex(0)}>
    🍎
  </Food>
  <Food name="Grape" isActive={activeIndex === 1} onShow={() => setActiveIndex(1)}>
    🍇
  </Food>
</>

Bên trong child component, ta sẽ không còn quản lý state nữa mà thay vào đó là dùng state và event handler của parent component:

function Food({ name, children, isActive, onShow }) {
  return (
    <section className="panel">
      <h3>{name}</h3>
      {isActive ? <p>{children}</p> : <button onClick={onShow}>Show</button>}
    </section>
  )
}

Controlled & Uncontrolled Components

Ta gọi các component mà sử dụng state cục bộ là các uncontrolled component. Ngược lại, controlled component là các component có dữ liệu được kiểm soát bởi parent component thông qua props.

Uncontrolled component thì không cần phải cấu hình nhiều và dễ sử dụng. Trong khi đó, controlled component thì linh hoạt hơn nhưng chúng ta cần phải cấu hình chúng thông qua props truyền vào từ parent component.

Resources