React Hook父组件获取子组件数据/函数
我们知道在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()调用函数了
React Hook父组件提交子组件form
父组件
import React, { useState, useEffect, useRef } from 'react'; import { Button } from 'antd'; import EditClassA from './EditClassA'; export default (): React.ReactNode => { const [isEdit,setIsEdit] = useState<boolean>(false); const editClassARef = useRef(); const handleSave = () => { // 调用子组件的方法 editClassARef.current.changeVal(); } return ( <div> {!isEdit?( <Button style={{marginRight:20}} onClick={()=>setIsEdit(!isEdit)}>编辑</Button> ):( <Button style={{marginRight:20}} onClick={handleSave}>保存</Button> )} </div> <EditClassA isEdit={isEdit} setIsEdit={setIsEdit} ref={editClassARef}/> ) }
子组件
import React, { useImperativeHandle, forwardRef } from 'react'; import { Form , Input } from 'antd'; import style from '@/pages/BackEnd/style.less'; const EditClassA = forwardRef((props, ref) => { // props 里面有父组件的值和方法 const [form] = Form.useForm(); useImperativeHandle(ref, () => ({ changeVal: () => { form .validateFields() .then( values => { // 调用父组件方法,设置父组件的值 props.setIsEdit(!props.isEdit) }) .catch(errorInfo => { return false }) } })); return ( <Form form={form} name="basic" colon={false} > <Form.Item label="总部名称" name="name" initialValue="总部" rules={[{required: true,message: '请输入总部名称',}]}> <Input className={props.isEdit?'':style.disabledInput} placeholder="请输入" disabled={!props.isEdit}/> </Form.Item> </Form> ); }) export default EditClassA
.disabledInput[disabled]{ color: rgba(0, 0, 0, 0.85); background-color: transparent; cursor: default; border: unset; border-bottom: 1px solid #333; }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。