我们知道在react中,常用props实现子组件数据到父组件的传递,但是父组件调用子组件的功能却不常用。文档上说ref其实不是最佳的选择,但是想着偷懒不学redux,在网上找了很多教程,要不就是hook的讲的太少,要不就是父子组件傻傻分不清,于是只好再啃了一下文档,就学了一下其它hook的api。

在这里我们需要用到useImperativeHandle这个api,其函数形式为

useImperativeHandle(ref, createHandle, [deps])


其实这个api也是ref的一种形式,但是相当于做了一定的优化,可以选择让子组件只暴露一定的api给父组件,根据在文档和其他博客上给出的方法,一共有两大步骤:

  1. 将ref传递到子组件中
  2. 需要使用forwardRef对子组件进行包装


 


子组件MyWorldMap

 const mapRef = useRef(null);
useImperativeHandle(ref, () => {

return {
//clickSwitch是子组件暴露的函数
clickSwitch() {

if(type == 1){
initChinaMap();
setType(2);
}else{
initWordMap();
setType(1);
}

}
}
})

//你的return内容,注意ref

return(
<react.Fragment>

<div id={"myWorldMap"} style={{ width: "800px", height: "400px" }} ref={mapRef}></div>

</React.Fragment>


)
}


//最后要配合forwardRef
MyWorldMap = forwardRef(MyWorldMap);
export default MyWorldMap;


注:ref是子组件声明的时候传进来的,也就是

function MyWorldMap (props,ref){
//..你的代码
}

//export...


其实官方文档给出来的例子是:

function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);


两种方法都是可以的

父组件MyTrip

const myWordMapRef = useRef();

return(
//省略一些代码,注意ref
<MyWorldMap proData = { myMapData} handleMapClick = {handleMapClick.bind(this)} ref={myWordMapRef}>

</MyWorldMap>
<div className={styles["mapButton-wrap"]}>
<ButtonGroup>
<Button onClick={() => myWordMapRef.current.clickSwitch()}>Switch</Button>
<Button onClick={()=>clickAll() }>All</Button>
</ButtonGroup>
</div>
)


现在你就可以在父组件里面通过myWordMapRef.current.clickSwitch()调用函数了