ForwardRef?useImperativeHandle方法demo
一、獲取Ref的方式
- 使用字符串
- 使用函數(shù)
- 使用Ref對(duì)象(最常見(jiàn))
- 使用createRef
export class RefTest extends React.Component { currentDom: React.RefObject<HTMLDivElement> = React.createRef(); currentChildren: React.LegacyRef<Children> = React.createRef(); render() { console.log(this.currentChildren, this.currentDom); return ( <> <div ref = { this.currentDom }>你好</div> <Children ref = { this.currentChildren}></Children> </> ) } }
- 使用useRef
export const RefTest = () => { const currentDom = useRef(null); const currentChildren = useRef(null); useEffect(() => { console.log(currentChildren, currentDom, '這里也可以打印出來(lái)了'); },[]) return ( <> <div ref = { currentDom }>你好</div> <Children ref = { currentChildren }></Children> </> ) }
二、Ref實(shí)現(xiàn)組件通信
- 既然ref可以獲取到子組件的實(shí)例,那么就可以拿到子組件上的狀態(tài)和方法,從而可以實(shí)現(xiàn)組件之間的通信
來(lái)個(gè)極簡(jiǎn)版
import React, { useEffect } from 'react'; class Son extends React.Component{ state={ sonValue:'' } render(){ return <div> <div>子組件的信息: {this.state.sonValue}</div> <div>對(duì)父組件說(shuō)</div> <input onChange{(e)=>this.props.setFather(e.target.value)}/> </div> } } export default function Father(){ const [ fatherValue , setFatherValue ] = React.useState('') const sonRef = React.useRef(null) return <div> <div>父組件的信息: {fatherValue}</div> <div>對(duì)子組件說(shuō)</div> <input onChange = { (e) => sonRef.current.setState( {sonValue: e.target.value})}/> <Son ref={sonRef} setFather={setFatherValue}/> </div> }
三、ForwardRef
- 上面說(shuō)的三種都是組件去獲取其DOM元素或者子組件的實(shí)例,當(dāng)開(kāi)發(fā)變得復(fù)雜時(shí),我們可能有將ref跨層級(jí)捕獲的需求,也就是可以將ref進(jìn)行轉(zhuǎn)發(fā)
比如跨層級(jí)獲取ref信息
- 來(lái)個(gè)例子, 我們希望能夠在GrandFather組件獲取到Son組件中
![圖片轉(zhuǎn)存失敗,建議將圖片保存下來(lái)直接上傳 import React from 'react'; interface IProps { targetRef: React.RefObject<HTMLDivElement> otherProps: string } interface IGrandParentProps { otherProps: string } class Son extends React.Component<IProps> { constructor(props) { super(props); console.log(props,'son中的props'); } render() { // 最終目標(biāo)是獲取該DOM元素的信息 return <div ref= { this.props.targetRef }>真正目的是這個(gè)</div> } } class Farther extends React.Component<IProps> { constructor(props) { super(props) console.log(props, 'father中的props'); } render() { return ( // 繼續(xù)將ref傳給Son <Son targetRef={this.props.targetRef} {...this.props} /> ) } } // 在這里使用了forwardRef, 相當(dāng)于把傳入的ref轉(zhuǎn)發(fā)給Father組件 const ForwardRef = React.forwardRef((props: IGrandParentProps, ref: React.RefObject<HTMLDivElement>) => <Farther targetRef={ref} {...props}/>) image.png(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5d49e7ff4ec940b28dcb3a780fd5c0a7~tplv-k3u1fbpfcp-watermark.image?) export class GrandFather extends React.Component { currentRef:React.RefObject<HTMLDivElement> = React.createRef(); componentDidMount() { // 獲取到的Ref信息 console.log(this.currentRef, 'componentDidMount'); } render() { return ( <ForwardRef ref={this.currentRef} otherProps = '正常傳遞其他props' /> ) } } ]()
- 打印結(jié)果: 其實(shí)就是利用了forwardRef,把 ref 變成了可以通過(guò) props 傳遞和轉(zhuǎn)發(fā)
四、 useImperativeHandle
- 上面我們一直說(shuō)的都是獲取子組件的實(shí)例,但是實(shí)際上我們函數(shù)組件是沒(méi)有實(shí)例的,故我們需要借助useImperativeHandle, 使用forwardRef+useImperativeHandle就可以在函數(shù)組件中流暢地使用ref
- useImperativeHandle可以傳入三個(gè)參數(shù):
- ref: 可以接受forwardRef傳入的ref
- handleFunc: 返回值作為暴露給父組件的ref對(duì)象
- deps: 依賴(lài)項(xiàng),當(dāng)依賴(lài)項(xiàng)改變的時(shí)候更新形成的ref對(duì)象
看完參數(shù)其實(shí)就能夠清楚地知道它的作用了,可以通過(guò)forwardRef+useImperativeHandle自定義獲取到的ref信息
再來(lái)兩個(gè)簡(jiǎn)單例子:
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react" const ForwardItem = forwardRef((props, ref) => { const [sonValue, setSonValue] = useState('修改之前的值'); useImperativeHandle(ref, () => ({ setSonValue, })) return ( <div>子組件的值: {sonValue}</div> ) }) export const Father = () => { const testRef = useRef(null); useEffect(() => { console.log(testRef.current, 'ref獲取到的信息') }) const changeValue = () => { const DURATION = 2000; setTimeout(() => { testRef.current.setSonValue('我已經(jīng)修改值啦') },DURATION) } return ( <> <ForwardItem ref={ testRef }/> <button onClick={() => changeValue()}>2s后修改子組件ForwardItem的值</button> </> ) }
- 父組件希望直接調(diào)用函數(shù)子組件的方法
- 這里讓useImperativeHandle形成了有setSonValue的ref對(duì)象,然后再在父組件調(diào)用該方法
- 父組件希望獲取到子組件的某個(gè)DOM元素
const ForwardItem = forwardRef((props, ref) => { const elementRef: RefObject<HTMLDivElement> = useRef(); useImperativeHandle(ref, () => ({ elementRef, })) return ( <div ref = { elementRef }>我是一個(gè)子組件</div> ) }) export const Father = () => { const testRef = useRef(null); useEffect(() => { console.log(testRef.current, 'ref獲取到的信息') }) return ( <> <ForwardItem ref={ testRef }/> </> ) }
當(dāng)然useRef還可以在函數(shù)組件中緩存數(shù)據(jù),這個(gè)就不多叨叨啦,更多關(guān)于ForwardRef useImperativeHandle的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React+Node實(shí)現(xiàn)大文件分片上傳、斷點(diǎn)續(xù)傳秒傳思路
本文主要介紹了React+Node實(shí)現(xiàn)大文件分片上傳、斷點(diǎn)續(xù)傳秒傳思路,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02關(guān)于react ant 組件 Select下拉框 值回顯的問(wèn)題
這篇文章主要介紹了關(guān)于react ant 組件 Select下拉框 值回顯的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08React中常見(jiàn)的動(dòng)畫(huà)實(shí)現(xiàn)的幾種方式
本篇文章主要介紹了React中常見(jiàn)的動(dòng)畫(huà)實(shí)現(xiàn)的幾種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01ahooks封裝cookie?localStorage?sessionStorage方法
這篇文章主要為大家介紹了ahooks封裝cookie?localStorage?sessionStorage的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07使用React-Router時(shí)出現(xiàn)的錯(cuò)誤及解決
這篇文章主要介紹了使用React-Router時(shí)出現(xiàn)的錯(cuò)誤及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03在React中編寫(xiě)class樣式的方法總結(jié)
在TypeScript (TSX) 中編寫(xiě) CSS 樣式類(lèi)有幾種方法,包括使用純 CSS、CSS Modules、Styled Components 等,本文給大家介紹了幾種常見(jiàn)方法的示例,通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-07-07React videojs 實(shí)現(xiàn)自定義組件(視頻畫(huà)質(zhì)/清晰度切換) 的操作代碼
最近使用videojs作為視頻處理第三方庫(kù),用來(lái)對(duì)接m3u8視頻類(lèi)型,這里總結(jié)一下自定義組件遇到的問(wèn)題及實(shí)現(xiàn),感興趣的朋友跟隨小編一起看看吧2023-08-08React合成事件及Test Utilities在Facebook內(nèi)部進(jìn)行測(cè)試
這篇文章主要介紹了React合成事件及Test Utilities在Facebook內(nèi)部進(jìn)行測(cè)試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12