React-Hooks 初识 (四): useImperativeHandle,结合forwardRef 实现父组件调子组件的属性和方法
大家好,我是张添财。今天介绍的是useImperativeHandle,这个钩子函数和上篇的《useRef的使用》关联性较强,建议对useRef不熟悉的小伙伴们可以看下上篇useRef的介绍。好了,废话不多说,让我们一起开卷!!!
在我开始介绍如何useImperativeHandle使用之前,我们先来了解下forwardRef:转发Ref。
前置知识:forwardRef ---> 转发Ref
众所周知,我们在React里给函数式组件直接写ref属性时,控制台会报个警告,如下图:
让我这个英语专业十级翻译翻译(手动狗头~):不能为函数式组件提供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渲染函数里的第二个参数对应
;
- 第二个参数是个处理函数,它的返回值就是我们要传给父组件的方法和属性;
返回的是一个对象
- 第三个参数是依赖项,表示只有依赖项中的值发生改变,才会把最新的属性和方法传给父组件;如果没有依赖项,则表示只要子组件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。请各位小伙伴保持关注呐!
转载自:https://juejin.cn/post/7074761729753743373