工作中的一个工作,遇到了须要在 react 框架下父组件调用子组件办法的状况。这让我想起来在 vue 中是何其容易,只须要:定义子组件的属性 ref=”myChild”, 父组件通过:this.$refs.myChild. 子组件办法 (); 这样就能够间接在父组件中调用子组件的所有办法。
然而这 react 中并没有这么简略粗犷,因为 hook 曾经十分不便,react 开发摒弃类组件而应用函数组件,罕用的 hook,曾经在工作中应用,这次要做父组件调子组件办法,不得不动用一下那些不罕用的 hook 了。
先理一下思路:第一步在父组件中把子组件用 ref 绑定起来;第二步拿到子组件,用子组件调用它的办法。
实际:
一:在父组件中给子组件绑定 ref,有两种形式 useRef 和 createRef。
useRef 是用在函数组件中,createRef 只能用在类组件中,所以此时抉择 useRef。
import {useRef} from 'react'; // 引入
const childRef = useRef(); // 定义
<ChildComp ref={childRef} />// 绑定
接下来就能够用上面的代码来调子组件的办法了
childRef.current.focus();
官网的解释为:其 .current 属性被初始化为传入的参数
二:通过下面一步就能够调子组件办法了么?并不能。react 不像 vue 那样,你定义我为你儿子,你就能够调用我所有的办法。react 还须要接管 ref,意思是,你认我当儿子,我也得认你当爹。ref 须要像 props 一样,由父组件传递给子组件,子组件接管。
let Child = (ref) => {...}
三:接下来,要用到 hook 的 useImperativeHandle 了,这个的官网解释为:能够让你在应用 ref 时自定义裸露给父组件的实例值。也就是想给父组件调用的办法要写在 useImperativeHandle 外面,其中第一个参数 ref 是以后组件接管到的 ref 的援用。
useImperativeHandle(ref, () => ({
// changeVal 就是裸露给父组件的办法
changeVal: (newVal) => {...}
}));
四:原本到此曾经实现了父组件调用子组件的办法,然而官网中有这样说:在大多数状况下,该当防止应用 ref 这样的命令式代码。useImperativeHandle 该当与 forwardRef 一起应用。forwardRef 是什么呢,它是用来创立一个可能将其承受的 ref 属性转发到其组件树下的另一个组件中的组件,应用场景为以下两个:转发 refs 到 DOM 组件;高阶组件中转发 refs。我以后的场景并没有这两种状况,然而官网举荐 useImperativeHandle 该当与 forwardRef 一起应用,就这样应用,具体原因等我之后钻研。
全副代码如下:
/* 父组件 */
import {useRef} from 'react';
const Father = () => {const childRef = useRef();
const updateChildState = () => {childRef.current.changeVal(99);
}
return (
<>
<Child ref={childRef} />
<button onClick={updateChildState}> 触发子组件办法 </button>
</>
)
}
/* 子组件 */
import {useState, useImperativeHandle,forwardRef} from 'react';
let Child = (props,ref) => {useImperativeHandle(ref, () => ({changeVal: (newVal) => {}}));
return (<div>{val}</div>
)
}
ChildComp = forwardRef(ChildComp)