Re: 新手让网页 act 起来: Day27 - React Hooks 之 useImperativeHandle 与 React.forwardRef

前言

在 React hooks 中 useImperativeHandle 是一个相对较少使用的 hook,且使用它的时候也必须搭配着 React.forwardRef 来使用。如果是刚开始学 React 或是从来都没有仔细看手册的人,可能都不会知道有这个 hook 的存在,或是早就忘记它的存在。今天就让我来了解了解 useImperativeHandle,这个冷门又容易被遗忘的 hook 吧!或许了解之後,可能在某些情境下可以考虑使用它。

React.forwardRef

在开始介绍 useImperativeHandle 之前,先来介绍它的好搭档 forwardRef。forwardRef 与 memo 一样是个 HOC (High order component) ,接受一个元件并回传一个元件。

那为什麽需要 forwardRef 呢?直接来看下面的范例:

function App() {
  const inputRef = React.useRef()

  return (
    <div>
      <input type="text" ref={inputRef} />
    </div>
  )

}

ReactDOM.render(<App />, document.getElementById('root'))

在这个范例中,我们使用了 useRef 并在 input ref 属性挂上,以取得 input 的 DOM node。

那假设今天有种情况是需要将 input 抽象化成一个元件,并尝试将 ref 透过 props 传递下去,挂在 input 的 ref 上,如下

function InputField({ ref }) {
  return (
    <input type="text" ref={ref} />
  )
}

function App() {
  const inputRef = React.useRef()

  return (
    <div>
      <InputField ref={inputRef} />
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

这个时候打开 console 就会发现 React 丢出的错误讯息

在 function component 中是不能够将 ref 作为 props 传递的,这个时候 forwardRef 就登场啦!我们可以用 forwardRef 将元件包起来,他就会回传一个可以传递 ref 的元件给我们。

const InputField = React.forwardRef((props, ref) => {
  return (
    <input type="text" ref={ref} />
  )
})

改成这样子之後,我们就能够顺利取的 input DOM node 了!

useImperativeHandle

介绍完 forwardRef 的基本使用方式之後,我们再来看看 useImperativeHandle 在 React 官方的说明以及基本的用法

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

useImperativeHandle(ref, createHandle, [deps]))

简单来说,我们可以将子元件定义的变数或是函式,透过 useImperativeHandle 给父层传下来的 ref 定义属性。让我们直接看看使用范例:

const InputField = React.forwardRef((props, ref) => {
  const inputRef = React.useRef()

  React.useImperativeHandle(
    ref,
    () => {
      return {
        focus: () => {
          inputRef.current.focus()
        }
      }
    })


  return (
    <input type="text" ref={inputRef} />
  )
})

function App() {
  const InputFieldRef = React.useRef()

  function clickHandler() {
    InputFieldRef.current.focus()
  }

  return (
    <div>
      <button onClick={clickHandler}>focus</button>
      <InputField ref={InputFieldRef} />
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

在范例中,useImperativeHandle 第一个参数接收来自父层定义的 ref,然後我们在第二个 callback 参数必须回传一个物件,而这个物件就会成为父层 ref 中 current 属性的值。所以我们就在这个物件中定义了 focus 属性,让父层 ref 可以呼叫这个方法。

以上就是今天的分享,如果有任何问题都欢迎在下方留言!

该文章同步发布於:我的部落格


<<:  【Day27】线性收敛除法器实作

>>:  [28] 用 python 刷 Leetcode: 1013

[Day22]The 3n + 1 problem

上一篇介绍了Palindromes,上一题讲解了如何辨别是不是镜像字或是回文字的题目,只要先辨别出镜...

Day 29-制作购物车之Redux 4

主要呈现实作成果 以下内容有参考教学影片,底下有附网址。 (内容包括我的不专业解说分析及在实作过程中...

Day4 用MR体验现实世界中办不到的事情或是事先体验将要做的事情

上两期说到VR和AR,这期来介绍介於他们两个之间的MR。 MR(混合实境):MR是一种介於VR(虚拟...

Day5 - 找出适合自己的案子

当花了很多时间整理经营作品集後,得到主动来信询问真的会非常感动,可以感受到自己是被社会所需要的,在肯...

【DAY 3】 Microsoft 365 开发人员计画... 包山包海,但你需要知道你想要什麽

哈罗,大家好,欢迎跟着温秘书继续 Microsoft 365 开发人员计画。 在昨天完成基础设定後,...