forwardRef和useImperativeHandle

446 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情

接上篇,如果在父子组件之间传递ref转发,一般是在父组件中定义好,再传递给子组件使用。

如下:

App父组件

 const lastValue = useRef()
 ------------------------------
 <Child  inputRef={inputRef}/>

然后在子组件中通过传统的props接收inputRef

function Child(props){
    const {inputRef} = props
    return(
     <input type="text" ref={inputRef} />
    )
}

现使用新方式-------ref转发

在react中有一个forwardRef方式可以用来专门转发ref,使用方式如下:

同样在app组件中定义好useRef,

 const inputRef = useRef()//current:null

不同点:直接转发ref至子组件

要转发给哪个子组件,就包裹住谁

 const ForwardChild =  forwardRef(Child)

使用完转发方法,就可以在父组件中通过ref转发inputRef了

   <ForwardChild ref={inputRef}/>

原本是:记住差别哦

<Child  inputRef={inputRef}/>

接下来就可以跑去子组件中接收并使用ref啦

 function Child(props,ref){
            console.log(props,"props");
            console.log(ref,"ref");
            return(
                <input type="text" ref={ref}/>
            )
        }

此时打印props属性,它里面为空,因为通过forward方式就不会涉及到props传递了。

那打印第二个参数ref,可以观察到里面有current有inputRef了。

直接就可以在ref处引用父组件传来的“ref”咯

场景升级,当点击按钮时,进行获取焦点的操作:

 <ForwardChild ref={inputRef}/>
 <button onClick={focus}>按钮</button>

定义方法:

 const focus=()=>{
           inputRef.current.focus()
 }

点击就可以调用真实dom上的方法focus了。

那也可以点击按钮删除该真实dom

inputRef.current.parentNode.removeChild(inputRef.current)

这样很危险啊,如果随便定义方法都可以使用的话那岂不是赤裸裸了嘛。

于是引入新钩子函数useImperativeHandle转发权限

在转发权限中设置对象,內部可以有很多可以被允许的方法,只有在这里暴露的权限才能被使用,如果没有被定义过却仍然使用的话,那结果就是失败并报错。

步骤,来到子组件中,浅试一下,暴露两个方法吧

 const inputRef = useRef()
 const childHandle =()=>{
       console.log("child inner other function");
  }
  useImperativeHandle(ref,()=>{
     return{
         focus:()=>{
             inputRef.current.focus()
         },
         childHandle:()=>{
             childHandle
         }
     }
 })
 return(
   <input type="text" ref={inputRef}/>
     )

于是,就可以来到父组件中使用这两个被暴露的方法了

 const focus=()=>{
     inputRef.current.focus()
 }

此时如果再删除节点的话就会报错了。所以暴露权限成功。