React-Hooks 初识 (四): useImperativeHandle,结合forwardRef 实现父组件调子组件的属性和方法

  大家好,我是张添财。今天介绍的是useImperativeHandle,这个钩子函数和上篇的《useRef的使用》关联性较强,建议对useRef不熟悉的小伙伴们可以看下上篇useRef的介绍。好了,废话不多说,让我们一起开卷!!!

  在我开始介绍如何useImperativeHandle使用之前,我们先来了解下forwardRef:转发Ref。

前置知识:forwardRef ---> 转发Ref

  众所周知,我们在React里给函数式组件直接写ref属性时,控制台会报个警告,如下图:

image.png   让我这个英语专业十级翻译翻译(手动狗头~):不能为函数式组件提供refs。尝试访问此ref将会失败。是否使用React.forwardRef()? 从这段警示我们就可以看出,函数式组件要使用ref属性,就要用forwardRef,那么问题来了,forwardRef怎么用呢???

***知识点来了***:forwardRef 会创建一个React组件,这个组件能够将其接收的 ref 属性转发到其组件树下的另一个组件中。其目的就是希望可以在封装组件时,外层组件可以通过 ref 直接控制内层组件或元素的行为。

const SonComponent=forwardRef((props,refParams)=>{
		...
})
复制代码

React.forwardRef 接受渲染函数作为参数。React 将使用 props 和 ref 作为参数来调用此函数。会ref转发给其下的元素中

import React,{useRef,forwardRef} from 'react'

const SonComponent = forwardRef((props, refparams) => {
    return (
        <>
            <div>
                <input type="text" defaultValue={props.value} ref={refparams} />
                <button onClick={() => console.log(refparams.current)}>点击打印ref</button>
            </div>
        </>

    )
})

const FatherComponent = () => {
    const sonRef = useRef()
    return (
        <>
            <SonComponent ref={sonRef} value='这是子组件的value值' />
        </>
    )
}
复制代码

  分析: 在父组件FatherComponent中设置sonRef并传给了子组件的ref属性,在定义子组件时用forwardRef包裹渲染函数并传入props,refparamas两个参数,refparamas对应的是子组件的ref属性,并且SonComponent组件将ref转发给其内部的input 框,此时,点击按钮就可以获取到这个input框;

  好了,经过上面的demo我们就知道函数式组件用ref时要结合forwardRef来转发ref属性了。但是,有小伙伴肯定在想,就算转发了又能怎么样呢,函数式组件没有实例,父组件还是拿不到子组件的方法呐!这时候我们的正主就来了: useImperativeHandle 一个子组件向外暴露属性的钩子函数。

正题: useImperativeHandle --->父组件调子组件的属性和方法的钩子函数

用法:
const SonComponent = forwardRef((props, refparams) => {
useImperativeHandle(refparams, createHandle, [deps])
  ...
}
复制代码

使用 useImperativeHandle 钩子函数并传入三个参数:

  • 第一个参数是父组件传过来的ref,就是上面例子中的refparams注意:这第一个参数值要和forwardRef渲染函数里的第二个参数对应

image.png

  • 第二个参数是个处理函数,它的返回值就是我们要传给父组件的方法和属性;返回的是一个对象
  • 第三个参数是依赖项,表示只有依赖项中的值发生改变,才会把最新的属性和方法传给父组件;如果没有依赖项,则表示只要子组件render都会把属性和方法传给父组件。

好了,现在我们就可以把 forwardRef 知识点里的demo改造如下:

import React,{useRef,forwardRef} from 'react'

const SonComponent = forwardRef((props, refparams) => {
useImperativeHandle(refparams, () => {
    return {
      logSon: () => {
        console.log('测试');
      }
    }
  },[])
  
    return (
        <>
            <div>
                <input type="text" defaultValue={props.value} ref={refparams} />
                <button onClick={() => console.log(refparams.current)}>点击打印ref</button>
            </div>
        </>

    )
})

const FatherComponent = () => {
    const sonRef = useRef()
    
    useEffect(()=>{
          sonRef.current.logSon()  ----测试
    },[])
    
    return (
        <>
            <SonComponent ref={sonRef} value='这是子组件的value值' />
        </>
    )
}
复制代码

  至此,本次的useImperativeHandle的介绍就告一段落了,在实际开发中,用这几个钩子就完全可以了,但是,这里我要提出一个问题:怎么减少react里不必要的rerender???

  我们知道,在react中只要state或者组件的props发生改变,那么组件就会重新进行render.其下游的子组件也会进行render,这样太费性能,不符合实际开发需要。如此这般自然而然就引出我接下来想要分享的点:memo、useCallback和useMemo。请各位小伙伴保持关注呐!

猜你喜欢

转载自juejin.im/post/7074761729753743373