UseImperativeHandle Hook 安全简单的调用子组件的方法,处理命令式操作。

7 阅读2分钟

useImperativeHandle – React 中文文档

useImperativeHandle 这个Hook的作用。

官方解释:useImperativeHandle 是 React 中的一个 Hook,它能让你自定义由 ref 暴露出来的句柄。

官方中提到了ref,可以知道这个 Hook (钩子,后续我说的Hook===钩子)是用来联动其它的Hook的一个作用,也就是联动开发中十分常用的useRef 钩子,如果有需要useImperativeHandle的场景,则必须使用上useRef或者ref

官方的给出了示例代码,我就直接按照示例代码来做笔记:

首先给出我的总结可以自定义的将子组件的方法剥离出来,给父组件用,而不是给父组件一个完整的 dom对象,更加安全更加舒服的处理命令式操作。

文件结构为:

  • App.jsx; (父组件)
  • MyInput.jsx;(子组件)
App.jsx 
import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);
// 注意:这里的ref不是MyInput这个组件的dom对象,这个组件返回的dom对象是inputRef的
  function handleClick() {
    ref.current.focus();
    // 下方代码不起作用,因为 DOM 节点并未被暴露出来:
     ref.current.style.opacity = 0.5;
  }

  return (
    <form>
      <MyInput placeholder="Enter your name" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

MyInput.jsx

import { useRef, useImperativeHandle } from 'react';

function MyInput({ ref, ...props }) {
  const inputRef = useRef(null);
    // 注意:这里的inputRef才是input的dom对象,而ref是个劫匪抢掉了一些inputRef的功能。
  useImperativeHandle(ref, () => {
    return {
      focus() {
        inputRef.current.focus();
      },
      scrollIntoView() {
        inputRef.current.scrollIntoView();
      },
    };
  }, []);

  return <input {...props} ref={inputRef} />;
};

export default MyInput;

如果我还是看不懂,可能是把两个ref搞混了,那打印对应的结果看看:

打印的位置与对象打印结果
myinput.jsx inputRefcurrent: input
myinput.jsx ref:current: focus: ƒ focus(); scrollIntoView: ƒ scrollIntoView()
App.jsx refcurrent: focus: ƒ focus() ; scrollIntoView: ƒ scrollIntoView()

可以看到子组件中的input输入框自始至终都没有暴露给父组件使用,父组件用useRef获取的只有子组件中两个功能 focus()scrollIntoView(),这样成功控制了父组件的权限,或者说控制了子组件暴露出来的权柄。

官方还给出了一个功能,暴露你自己的命令式方法,其实就是搭积木,更加灵活一点,理解第一个方法,这个第二个一看就懂了。

最后附上官方文档useImperativeHandle – React 中文文档