iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
Modern Web

從Create到React—用來實作使用者介面的JavaScript函式庫系列 第 16

從useRef理解forwardRef再解說useImperativeHandle—目的與用法

  • 分享至 

  • xImage
  •  

本文章將包含以下內容

  • 為什麼需要forwardRef
    • 回顧useRef
    • 直接將ref加在component上
    • forwardRef說明
    • forwardRef使用步驟
  • useImperativeHandle介紹
    • useImperativeHandle使用方式
    • 為什麼需要useImperativeHandle
  • 小結

為什麼需要forwardRef

本小節將透過回顧useRef的範例以及ref加註在component的error message來回推使用forwardRef的使用時機。

回顧useRef

回顧一下useRef的用法,useRef用來存取實際DOM元素,以下透過ref的props可以得到實際DOM的element。

function App() {
  const divRefContrainer = useRef(null);
  return (
    <div className="test" ref={divRefContrainer}>嗨</div>
  )
}

直接將ref加在component上

那如果我們嘗試著將ref加到Component的話會發生什麼事呢?

觀看以下範例

import React, { useRef } from "react";
function InputField({ ref }) {
  return <input type="text" ref={ref} />;
}
export default function App() {
  const inputRef = useRef();
  return (
    <div className="App">
      <InputField ref={inputRef} />
    </div>
  );
}

如下圖


因此當我們想要讓父元件存取子元件的ref的時候就得需要forwardRef將其子元件的ref暴露給父元件使用

forwardRef說明

詳細說明可以參考

根據react Beta官方的解釋如下

forwardRef lets your component expose a DOM node to parent component with a ref.

大致意思是
如果想要讓父元件可以存取到子元件的DOM節點(DOM node)的話就得仰賴forwardRef的幫助,定義完component給fowardRef進行傳遞後,在父元件就能拿到子元件的節點了。

forwardRef使用步驟

  1. forwardRef包裹你的component
  2. component傳入props和ref
  3. 在父層透過ref來存取其DOM
import React, { useRef, forwardRef } from "react";
const ForwardRefMyInput = forwardRef(
  function InputField(props, ref) {
    return (
      <>
        <input {...props}
            ref={ref}
            type="text" />
      </>
    );
  }
)

export default function App() {
  const inputRef = useRef();
  const clickHandler = () => {
    console.log(inputRef.current);
  }
  return (
    <div className="App">
        <ForwardRefMyInput ref={inputRef} />
        <button onClick={clickHandler}>按鈕</button>
    </div>
  );
}

最後就能如願印出input元件了。

useImperativeHandle介紹

本小節將實現一個useImperativeHandle的範例來解說useImperativeHandle的使用方式

useImperativeHandle使用方式

通常可以讓父元件得到子元件某些自定義方法,根據react官方文件,此hook應當與forwordRef一起使用,換句話說,如果想要使用useImperativeHandle的話就得與useRef、forwardRef一起使用。

觀看以下程式碼

import React, { useRef, forwardRef, useImperativeHandle } from "react";
const ForwardRefMyInput = forwardRef(
  function InputField(props, ref) {
    const inputRef = useRef();
    useImperativeHandle(ref, () => ({
      focus: () => {
          inputRef.current.focus();
      }
    }));
    return (
      <>
        <input {...props}
          ref={inputRef}
          type="text" />
      </>
    );
  }
)
export default function App() {
  const parentInputRef = useRef();
  const clickHandler = () => {
    console.log(parentInputRef.current);
  }
  return (
    <div className="App">
      <ForwardRefMyInput ref={parentInputRef} />
      <button onClick={clickHandler}>按鈕</button>
    </div>
  );
}

透過自定義的function叫做focus函式回傳,我們父層就能透過宣告useRef的方式拿取子元件所暴露的方法,最後如下圖。

為什麼需要useImperativeHandle

當我們元件裡面有許多元素的時候

可以透過useImperativeHandle限制子元素所暴露的方法

另一方面也理解成指定useImperativeHandle所暴露的方法。

達到透過父元件操控子元件指定的DOM屬性。

小結

當我們實際在撰寫react的時候,如果要透過父元件操控子元件的某些屬性或方法的時候就得考慮useImperativeHandleforwardRef

以上如果解說有誤歡迎糾正。

參考資料

上一篇
React管理virtualDOM,為什麼還需要useRef?
下一篇
解決propDrilling問題—簡化consumer的useContext
系列文
從Create到React—用來實作使用者介面的JavaScript函式庫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言