工作中的一个工作,遇到了须要在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)