当前位置: 首页 > Web前端 > JavaScript

最奇葩的hooks:useImperativeHandle

时间:2023-03-26 21:52:57 JavaScript

估计大家对这几个HOOKS比较熟悉:useState、useEffect、useContext、useMemo。但是第一次看到useImperativeHandle的时候,一头雾水(这是什么鬼~~~)。1.这是什么?React官网对useImperativeHandle的介绍也比较简短。一句话总结:子组件可以使用useImperativeHandle让父组件输出任意数据。//FancyInput组件作为子组件constFancyInput=React.forwardRef(functionFancyInput(props,ref){constinputRef=useRef();//强制性地将一个对象分配给`ref.current`useImperativeHandle(ref,()=>({focus:()=>{inputRef.current.focus()}}));return})//作为父组件的示例组件functionExample(){constfancyInputRef=useRef()constfocus=()=>{fancyInputRef.current.focus()}return(<>)}二、如何使用?2.1语法useImperativeHandle(ref,createHandle,[deps])ref需要给ref对象赋值。createHandle:createHandle函数的返回值作为ref.current的值。[deps]依赖数组,如果依赖发生变化,会重新执行createHandle函数。2.2进阶:什么时候执行createHandle函数?测试发现useLayoutEffect的执行时机是一致的。修改下一个组件FancyInput的内容:constFancyInput=React.forwardRef(functionFancyInput(props,ref){constinputRef=useRef();console.log('render1')useLayoutEffect(()=>{console.log('useEffect1',ref)})useImperativeHandle(ref,function(){debuggerconsole.log('useImperativeHandle')return{focus:()=>{inputRef.current.focus();}}})useLayoutEffect(()=>{console.log('useEffect2',ref);})console.log('render2')return;})查看控制台输出到找到createHandle函数,执行时机和useLayoutEffect一致,保证了在useEffect的任意位置都能获取到最新的ref.current值。注意:执行createHandle函数有一个前提条件,即useImperativeHandle的第一个实参ref必须有值(否则执行createHandle函数是没有意义的)。2.3应用场景目前项目有多种使用场景,主要解决父组件获取子组件的数据或者调用子组件中声明的函数。例如formik库的一种使用:React.useImperativeHandle(innerRef,()=>formikbag);2.4BestPracticeReact官网给出了一些使用建议:尽量避免命令式赋值给ref.current,尽量使用declarationType(即让React内部处理);它不一定与forwardRef一起使用,例如上面的fomik库就没有这样做。3.原理回顾一下我们之前是如何使用ref的:一开始,我们使用ref来访问子组件实例或者DOM元素;后来useRef出现了,我们可以在函数组件中使用useRef来存储一些类似于成员变量的数据。让我们回顾一下React如何处理声明性引用:React会在组件挂载时将当前属性分配给DOM元素,并在组件卸载时将其重新分配回null。通过前面的知识,我们可以达成一些共识:给ref。Current赋值是一个副作用,所以ref.current一般是在Did函数或者事件处理函数中赋值;卸载组件时应清除ref.current的值。本质上useImperativeHandle就是在为我们做这些事情。4、为什么需要useImperativeHandle我们都知道,父组件可以通过ref访问子组件实例或DOM元素,实际上相当于子组件将自己的实例或DOM元素输出给父组件。使用useImperativeHandle子组件可以向父组件输出任意数据。整理自GitHub笔记:useImperativeHandle