React 裡的逆向資料流!使用 useImperativeHandle!

Avatar

David / 2022-10-20



React 裡的逆向資料流!使用 useImperativeHandle!
  • 我們一般在 React 裡面傳遞資料的時候,不管是透過 props 、 context 或是透過其他狀態管理套件像是 redux,通常都是保持著由上往下的資料流。

今天要來分享使用 react 的進階 hook :useImperativeHandle 來達成下往上的逆向資料流!

什麼是 useImperativeHandle ?

useImperativeHandle customizes the instance value that is exposed to parent components when using ref.

大概可以理解為 useImperativeHandle 讓我們可以自己把 child component 裡的東西自定義之後向外傳回給上一層的 parent component 使用。

React 讓我們能夠把一個一個複雜的邏輯包裝成 component ,讓我們可以把複雜的邏輯整理在與他們相關的位置。

像是如果有一個顯示照片的元件:`<PhotoGallery />` 裡面的 code 長這樣:

const PhotoGallery = () => {
  const [photo, setPhoto] = React.useState([])
  
  return photo.map((photo) => {
    return <Photo />
  })
}

那因為某種需求,我們需要在外面有一個按鈕,按了可以增加一張隨機照片照片,我們除了把 `const [photo, setPhoto] = React.useState([])` 移到外面一層,再把 `photo` 跟 `setPhoto` 當 props 傳進來,還有其他方法嗎?

有的,useImperativeHandle 的出現讓我們可以讓我們可以把 photo state 留在 `PhotoGallery` 裡,也能共享 `setPhoto` 的 function。

如何使用 useImperativeHandle ?

首先 useImperativeHandle 需要搭配 forwardRef 一起使用,所以我們在 PhotoGallery 加上 forwardRef,並且把 addPhoto 利用 useImperativeHandle bind 在這個 ref 上

const PhotoGallery = React.forwardRef((props, ref) => {
  const [photo, setPhoto] = React.useState([])
  
  React.useImperativeHandle(ref, () => {
    addRandomPhoto: () => {
      setPhoto((prevState) => prevState.push(randomPhoto))
    }
  }, [setPhoto])
  
  return photo.map((photo) => {
    return <Photo />
  })
})

接著在父層的位置把 ref 傳進 <PhotoGallery />,就可以在這邊取用 <PhotoGallery /> 裡 bind 的 function:

// Parent Component
const Parent = () => {
  const photoGalleryRef = React.useRef()
  
  const addRandomPhotoInPhotoGallery = () => {
    photoGalleryRef.current.addRandomPhoto()
  }
  
  return (
      <>
        <button
            onClick={addRandomPhotoInPhotoGallery}
        />
        <PhotoGallery ref={photoGalleryRef} />
      </>
  )
}

這樣我們就成功的把 state 留在相關的位置,讓 Parent 那邊的程式碼比較乾淨!

參考資料

  1. 官方文件