React操作DOM之forwardRef問題
React操作DOM之forwardRef
React操作DOM有幾種方式,傳入字符串,傳入一個對象(react推薦的方式),傳入一個函數(shù),今天就講一下使用react封裝過的高階組件forwardRef來操作DOM
首先導(dǎo)入
import React, { PureComponent,createRef,forwardRef } from 'react'然后const一個函數(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()}>點擊</button>
</div>
)
}
printRef(){
console.log(this.profileRef.current)
}
}
當(dāng)我們點擊按鈕時候

用這個的好處是什么?因為我們之前操作dom,函數(shù)式組件是不行的,因為它沒有實例,用這個高階組件就能完美解決這個問題
React forwardRef使用方法
作用與注意點
- 傳遞ref,把自身的ref綁定到其他地方(e.g. 你把文件交給總裁秘書,總裁秘書把文件交給總裁)
- ref 和 key 有點特殊,不會作為props參數(shù)向下傳遞,this.props拿不到ref對象
- 函數(shù)組件是沒有實例的,可以用useImperativeHandle實現(xiàn)部分功能
- 高階組件需做特殊處理

父 -> 子 -> 子(Dom)

import React, { useRef } from 'react';
import Content from './content';
const Home = () => {
// 創(chuàng)建一個Ref對象
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會作為第二個參數(shù),接收傳進來的ref屬性
* e.g.
* <Content count={count} user={user} ref={connectRef}>
*
* @param props - {count, user}
* @param ref - connectRef
* */
const Content = (props, ref) => {
return (
<div>
{/* 把ref綁定給傳進來的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)建一個Ref對象
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會作為第二個參數(shù),接收傳進來的ref屬性
* e.g.
* <Content count={count} user={user} ref={connectRef}>
*
* @param props - {count, user}
* @param ref - connectRef
* */
const Content = (props, ref) => {
return (
<div>
{/* 把ref綁定給傳進來的ref ≈ ref={connectRef} */}
<Header ref={ref} /> {/* class組件 */}
{/* <Footer ref={ref} /> 函數(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ù)為組件,返回值是新組件(增強過的組件)
- 高階組件會把所有接收到的props,傳遞給被包裝的組件(透傳)
- ref 和 key 類似,不是一個prop,所以不會透傳,ref會綁定到外層的高階組件上
- 高階組件可以嵌套多層,e.g. Hoc1(Hoc2(Hoc3(Content)))
所以為了把ref傳遞給最里面的組件,有兩種方法
- 在最外層用 forwardRef 對 ref 對象進行處理,ref -> ref -> props.key = ref
- 不用 ref,用自定義props承載 ref 對象,props.key = ref
/*
處理ref
e.g. Hoc1(Hoc2(Content))
<Content ref={myRef} /> 給Content綁定的ref會綁定到Hoc1上,且不會繼續(xù)向下傳遞
第一種方法 React.forwardRef ===============
在 Hoc1外面 用React.forwardRef()對ref做處理,用props來傳遞ref
0. 在高階組件外面包裹forwardRef,攔截獲取ref,增加一個props(xxx={ref}),真實組件通過props.xxx獲取
1. 使用時傳 ref={XXXX} // 和第二種方法不同的地方
2. 用forwardRef的第二個參數(shù)獲取 ref
3. 增加一個新的props,用來向下轉(zhuǎn)發(fā)ref e.g. forwardedRef={ref}
4. 真實組件中綁定 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的第二個入?yún)⒖梢越邮誶ef,在Hoc外層對ref做處理
export default React.forwardRef((props, ref) => {
const Wrapper = withRouter(Content); // Hoc
// forwardRef包裹的是Wrapper
// 需要在Wrapper中把ref向下傳遞給真實組件
// Wrapper中增加一個props屬性,把ref對象作為props傳給子組件
return <Wrapper {...props} forwardedRef={ref} />;
});
第二種方法 ==========
0. 使用時就用一個props來保存ref
1. 使用時傳 xxx={ref} // 和第一種方法的不同點
2. 真實組件中綁定 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>
);
};
// 包裝過程
export default Hoc(Content);
* */
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
React中g(shù)etDefaultProps的使用小結(jié)
React中的getDefaultProps功能允許開發(fā)者為類組件定義默認屬性,提高組件的靈活性和容錯性,本文介紹了getDefaultProps的作用、語法以及最佳實踐,并探討了其他替代方案,如函數(shù)組件中的默認參數(shù)、高階組件和ContextAPI等,理解這些概念有助于提升代碼的可維護性和用戶體驗2024-09-09
詳解在React中跨組件分發(fā)狀態(tài)的三種方法
這篇文章主要介紹了詳解在React中跨組件分發(fā)狀態(tài)的三種方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
React-Native之截圖組件react-native-view-shot的介紹與使用小結(jié)
這篇文章主要介紹了React-Native之截圖組件react-native-view-shot的介紹與使用小結(jié),需本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,要的朋友可以參考下2021-08-08

