React 裡的逆向資料流!使用 useImperativeHandle!
David / 2022-10-20
- 我們一般在 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 那邊的程式碼比較乾淨!