ReactHook之forwardRef和useInperativeHandle

341 阅读1分钟

1. forwardRef

forwardRef 允许组件使用 refDOM 节点暴露给父组件

【案例】:聚焦文本输入框

const DanoChirld=(props:any)=>{  
       return(<Input ref={props.ref}></Input>)  
   }  
     
  
const Damo = () => {  
    const butRef=useRef(null)  
    return (  
        <div>  
            <DanoChirld ref={butRef}/>  
            <Button onClick={()=>{  
             console.log(butRef.current)   
            }}>编辑</Button>  
        </div>  
    );  
}  
  
export default Damo;

直接通过将ref传参到函数子组件,报错!!!

image.png

控制台报错,说函数组件不能接受ref的外部数据。打印出子组件的propsref:undifineref没进来。外边虽然传了一个ref,但是一个函数组件找不到这个ref,读不到。

image.png

【原因】: 函数组件无法接收ref的props

【解决办法】:使用 forwardRef传递ref

如果你的函数组件想要接受别人传来的ref参数,就必须把函数组件用 forwardRef 包起来。这样就可以接受ref作为第二个参数。不然就只有props这一个参数。forwardRef 会把别人传给你的ref帮你传进来。

const DanoChirld=forwardRef((props:any,ref:any)=>{  
    return(<Input ref={ref}></Input>)  
})

const Damo = () => {  
    const butRef=useRef(null)  
    return (  
        <div>  
            <DanoChirld ref={butRef}/>  
            <Button onClick={()=>{  
             console.log(butRef.current)   
             butRef.current.focus()//聚焦
            }}>编辑</Button>  
        </div>  
    );  
}  
  
export default Damo;

image.png

【注】: 类组件是不需要的,可以直接传

2.useInperativeHandle

通过ref暴露子组件中的方法

image.png

image.png

const DanoChirld = forwardRef((props: any, ref: any) => {  
    const inputRef = useRef(null)  
    const focusFun = () => {  
        inputRef.current.focus()  
    }  
    useImperativeHandle(ref, () => {  
        return {  
            focusFun  
        }  
    })  
    return (<Input ref={inputRef}></Input>)  
})  
  
  
const Damo = () => {  
    const butRef = useRef(null)  
    return (  
        <div>  
            <DanoChirld ref={butRef} />  
            <Button onClick={() => {  
                butRef.current.focusFun()  
                console.log(butRef.current)  
            }}>编辑</Button>  
        </div>  
    );  
}  
  
export default Damo;

console.log(butRef.current)

企业微信截图_17170527271084.png

【注】:

  • forwardRefuseImperativeHandle配合使用将子组件的方法暴露给父组件;
  • 子传父通信也是同理!
const DanoChirld = forwardRef((props: any, ref: any) => {  
    const inputRef = useRef<InputRef>(null)  
    const [value,setValue] = useState("")  
    useImperativeHandle(ref, () => {  
        return {  
            focusFun(){  
                inputRef.current?.focus()  
            },  
            value  
        }  
    },[value])  
    return (<Input ref={inputRef} value={value} onChange={({target:{value}})=>{setValue(value)}}></Input>)  
})  
  
  
const Damo = () => {  
    const butRef = useRef<{focusFun(): void;value:string}>(null)  
    return (  
        <div>  
            <DanoChirld ref={butRef} />  
            <Button onClick={() => {  
                butRef.current?.focusFun()  
                console.log(butRef.current)  
            }}>编辑</Button>
            <Button type='default' onClick={()=>{
            console.log(butRef.current?.value);  
            }}>value</Button>  
        </div>  
    );  
}  
  
export default Damo;

image.png