React操作DOM之forwardRef問(wèn)題
React操作DOM之forwardRef
React操作DOM有幾種方式,傳入字符串,傳入一個(gè)對(duì)象(react推薦的方式),傳入一個(gè)函數(shù),今天就講一下使用react封裝過(guò)的高階組件forwardRef來(lái)操作DOM
首先導(dǎo)入
import React, { PureComponent,createRef,forwardRef } from 'react'
然后const一個(gè)函數(shù)組件,將它作為App的子組件
const Profile = forwardRef(function (props,ref){ return <h2 ref={ref}>Profile</h2> })
定義App組件
export default class App extends PureComponent { constructor(props){ super(props); this.profileRef = createRef() } render() { return ( <div> <Profile ref={this.profileRef} name={'lsh'}/> <button onClick={e=>this.printRef()}>點(diǎn)擊</button> </div> ) } printRef(){ console.log(this.profileRef.current) } }
當(dāng)我們點(diǎn)擊按鈕時(shí)候
用這個(gè)的好處是什么?因?yàn)槲覀冎安僮鱠om,函數(shù)式組件是不行的,因?yàn)樗鼪](méi)有實(shí)例,用這個(gè)高階組件就能完美解決這個(gè)問(wèn)題
React forwardRef使用方法
作用與注意點(diǎn)
- 傳遞ref,把自身的ref綁定到其他地方(e.g. 你把文件交給總裁秘書(shū),總裁秘書(shū)把文件交給總裁)
- ref 和 key 有點(diǎn)特殊,不會(huì)作為props參數(shù)向下傳遞,this.props拿不到ref對(duì)象
- 函數(shù)組件是沒(méi)有實(shí)例的,可以用useImperativeHandle實(shí)現(xiàn)部分功能
- 高階組件需做特殊處理
父 -> 子 -> 子(Dom)
import React, { useRef } from 'react'; import Content from './content'; const Home = () => { // 創(chuàng)建一個(gè)Ref對(duì)象 const connectRef = useRef(null); const handleFoucus = () => { const _ref = connectRef.current; _ref.focus(); }; return ( <div> <button onClick={() => handleFoucus()}> 使用子組件中DOM元素的方法 </button> <Content ref={connectRef} /> </div> ); }; export default Home;
import React, { forwardRef } from 'react'; /** * forwardRef包裹后,ref會(huì)作為第二個(gè)參數(shù),接收傳進(jìn)來(lái)的ref屬性 * e.g. * <Content count={count} user={user} ref={connectRef}> * * @param props - {count, user} * @param ref - connectRef * */ const Content = (props, ref) => { return ( <div> {/* 把ref綁定給傳進(jìn)來(lái)的ref ≈ ref={connectRef} */} <input type="password" ref={ref} /> </div> ) }; export default forwardRef(Content);
父 -> 子 -> 子(class)
import React, { useRef } from 'react'; import Content from './content'; const Home = () => { // 創(chuàng)建一個(gè)Ref對(duì)象 const connectRef = useRef(null); const handleAdd = () => { const _ref = connectRef.current; const { count } = _ref.state; _ref.setState({ count: count + 1 }) }; return ( <div> <button onClick={() => handleAdd()}> 使用子組件中class組件的屬性和方法 </button> <Content ref={connectRef} /> </div> ); }; export default Home;
import React, { forwardRef } from 'react'; import Header from './header'; import Footer from './footer'; /** * forwardRef包裹后,ref會(huì)作為第二個(gè)參數(shù),接收傳進(jìn)來(lái)的ref屬性 * e.g. * <Content count={count} user={user} ref={connectRef}> * * @param props - {count, user} * @param ref - connectRef * */ const Content = (props, ref) => { return ( <div> {/* 把ref綁定給傳進(jìn)來(lái)的ref ≈ ref={connectRef} */} <Header ref={ref} /> {/* class組件 */} {/* <Footer ref={ref} /> 函數(shù)組件是沒(méi)有實(shí)例的,所以connectRef.current: null */} </div> ) }; export default forwardRef(Content)
import React from 'react'; export default class Header extends React.Component { state = { count: 0 }; render() { return ( <div> {this.state.count} </div> ) } };
高階組件中的特殊情況
- 高階組件本質(zhì)是函數(shù),參數(shù)為組件,返回值是新組件(增強(qiáng)過(guò)的組件)
- 高階組件會(huì)把所有接收到的props,傳遞給被包裝的組件(透?jìng)鳎?/li>
- ref 和 key 類(lèi)似,不是一個(gè)prop,所以不會(huì)透?jìng)鳎瑀ef會(huì)綁定到外層的高階組件上
- 高階組件可以嵌套多層,e.g. Hoc1(Hoc2(Hoc3(Content)))
所以為了把ref傳遞給最里面的組件,有兩種方法
- 在最外層用 forwardRef 對(duì) ref 對(duì)象進(jìn)行處理,ref -> ref -> props.key = ref
- 不用 ref,用自定義props承載 ref 對(duì)象,props.key = ref
/* 處理ref e.g. Hoc1(Hoc2(Content)) <Content ref={myRef} /> 給Content綁定的ref會(huì)綁定到Hoc1上,且不會(huì)繼續(xù)向下傳遞 第一種方法 React.forwardRef =============== 在 Hoc1外面 用React.forwardRef()對(duì)ref做處理,用props來(lái)傳遞ref 0. 在高階組件外面包裹forwardRef,攔截獲取ref,增加一個(gè)props(xxx={ref}),真實(shí)組件通過(guò)props.xxx獲取 1. 使用時(shí)傳 ref={XXXX} // 和第二種方法不同的地方 2. 用forwardRef的第二個(gè)參數(shù)獲取 ref 3. 增加一個(gè)新的props,用來(lái)向下轉(zhuǎn)發(fā)ref e.g. forwardedRef={ref} 4. 真實(shí)組件中綁定 ref={props.forwardedRef} const Home = (props) => { const connectRef = useRef(null); return ( <div> <Content ref={connectRef} /> </div> ); }; // 被包裝組件 const Content = (props) => { return ( <div> <input type="password" ref={props.forwardedRef} /> </div> ); }; // forwardRef的第二個(gè)入?yún)⒖梢越邮誶ef,在Hoc外層對(duì)ref做處理 export default React.forwardRef((props, ref) => { const Wrapper = withRouter(Content); // Hoc // forwardRef包裹的是Wrapper // 需要在Wrapper中把ref向下傳遞給真實(shí)組件 // Wrapper中增加一個(gè)props屬性,把ref對(duì)象作為props傳給子組件 return <Wrapper {...props} forwardedRef={ref} />; }); 第二種方法 ========== 0. 使用時(shí)就用一個(gè)props來(lái)保存ref 1. 使用時(shí)傳 xxx={ref} // 和第一種方法的不同點(diǎn) 2. 真實(shí)組件中綁定 ref={props.xxx} const Home = (props) => { const connectRef = useRef(null); return ( <div> <Content forwardedRef={connectRef} /> </div> ); }; // 定義高階組件 export const Hoc = (WrappedComponent) => { class Wrapper extends React.Component { render() { return <WrappedComponent {...props} /> } } } // 被包裝的組件 const Content = (props) => { return ( <div> <input type="password" ref={props.forwardedRef} /> </div> ); }; // 包裝過(guò)程 export default Hoc(Content); * */
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
React中g(shù)etDefaultProps的使用小結(jié)
React中的getDefaultProps功能允許開(kāi)發(fā)者為類(lèi)組件定義默認(rèn)屬性,提高組件的靈活性和容錯(cuò)性,本文介紹了getDefaultProps的作用、語(yǔ)法以及最佳實(shí)踐,并探討了其他替代方案,如函數(shù)組件中的默認(rèn)參數(shù)、高階組件和ContextAPI等,理解這些概念有助于提升代碼的可維護(hù)性和用戶(hù)體驗(yàn)2024-09-09詳解在React中跨組件分發(fā)狀態(tài)的三種方法
這篇文章主要介紹了詳解在React中跨組件分發(fā)狀態(tài)的三種方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08基于Webpack4和React hooks搭建項(xiàng)目的方法
這篇文章主要介紹了基于Webpack4和React hooks搭建項(xiàng)目的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02React-Native之截圖組件react-native-view-shot的介紹與使用小結(jié)
這篇文章主要介紹了React-Native之截圖組件react-native-view-shot的介紹與使用小結(jié),需本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,要的朋友可以參考下2021-08-08在?React?Native?中給第三方庫(kù)打補(bǔ)丁的過(guò)程解析
這篇文章主要介紹了在?React?Native?中給第三方庫(kù)打補(bǔ)丁的過(guò)程解析,有時(shí)使用了某個(gè)React Native 第三方庫(kù),可是它有些問(wèn)題,我們不得不修改它的源碼,本文介紹如何修改源碼又不會(huì)意外丟失修改結(jié)果的方法,需要的朋友可以參考下2022-08-08如何用react優(yōu)雅的書(shū)寫(xiě)CSS
這篇文章主要介紹了如何用react優(yōu)雅的書(shū)寫(xiě)CSS,幫助大家更好的理解和學(xué)習(xí)使用react,感興趣的朋友可以了解下2021-04-04