1. 程式人生 > 其它 >web前端高階React - React從入門到進階之Refs&DOM以及Refs轉發

web前端高階React - React從入門到進階之Refs&DOM以及Refs轉發

技術標籤:ReactWEB前端框架refsrefs轉發forwardRefcreateRefuseRef

第二部分:React進階

系列文章目錄

第一章:React從入門到進階之初識React
第一章:React從入門到進階之JSX簡介
第三章:React從入門到進階之元素渲染
第四章:React從入門到進階之JSX虛擬DOM渲染為真實DOM的原理和步驟
第五章:React從入門到進階之元件化開發及Props屬性傳值
第六章:React從入門到進階之state及元件的生命週期
第七章:React從入門到進階之React事件處理
第八章:React從入門到進階之React條件渲染
第九章:React從入門到進階之React中的列表與key


第十章:React從入門到進階之表單及受控元件和非受控元件
第十一章:React從入門到進階之元件的狀態提升
第十二章:React從入門到進階之元件的組合使用
第十三章:React從入門到進階之元件的元件的懶載入及上下文Context
第十四章:React從入門到進階之Refs&DOM以及Refs轉發

文章目錄

什麼是Refs

Refs提供了一種方式,運許我們訪問DOM節點或在render方法中建立的React元素
在典型的React資料流中,props是父元件與子元件互動的唯一方式。要想修改一個子元件,我們需要使用新的props來重新渲染。但是在某些情況下,我們不得不在典型資料流之外去修改一些子元件。被修改的子元件可能是一個React元件的例項,也可能是一個DOM元素。這種情況下我們就必須要考慮其它方式了。好在React為我們提供瞭解決辦法。

什麼時候使用Refs

以下幾種情況適合使用refs:

  • 管理焦點,文字選擇或媒體播放
  • 觸發強制動畫
  • 整合第三方DOM庫

refs雖然能夠讓我們去操作DOM元素,但是在實際開發中不要過度使用refs,也就是說能不用refs的就儘量不要使用

Refs的使用

  • 建立Refs

Refs 是用React.createRef()來建立的,並通過 ref 屬性附加到 React 元素。在構造元件時,通常將 Refs 分配給例項屬性,以便可以在整個元件中引用它們。

class RefComponent extends React.Component{
	constructor(props){
		super
(props); this.myRef = React.createRef(); } render(){ return <div ref={this.myRef} /> } }
  • 訪問Refs

訪問ref的方式也很簡單,當ref被傳遞給render中的元素時,對該節點的引用可以在 ref 的 current 屬性中被訪問。也就是說我們建立的ref會有一個current屬性,那麼我們所要操作的元素就存在這個current中。
ref的值根據節點的型別有所不同:

  • 當ref屬性用於HTML元素時,建構函式中使用React.createRef()建立的ref接收底層DOM元素作為其current屬性。
  • 當ref屬性用於自定義Class元件時,ref物件接收元件的掛載例項作為其current屬性。
  • **注意:**我們不能在函式元件上使用ref屬性,因為它們沒有例項
    下面來看兩個案例:
  • 為DOM元素新增ref
class CustomTextInput extends React.Component {
	constructor(props) {
    	super(props);
    	//建立一個ref來儲存DOM元素
    	this.textInput = React.createRef();
    }
    focusTextInput = ()=>{
	    // 直接使用原生 API 使 text 輸入框獲得焦點
	    // 注意:我們通過 "current" 來訪問 DOM 節點
    	this.textInput.current.focus();
    }
    render() {
	    // 告訴 React 我們想把 <input> ref 關聯到
	    // 構造器裡建立的 `textInput` 上
	      return (
	      <div>
	        <input
	          type="text"
	          ref={this.textInput} />
	        <input
	          type="button"
	          value="Focus the text input"
	          onClick={this.focusTextInput}
	        />
	      </div>
    );
	}
}

React 會在元件掛載時給 current 屬性傳入 DOM 元素,並在元件解除安裝時傳入 null 值。ref 會在 componentDidMount 或 componentDidUpdate 生命週期鉤子觸發前更新。

  • 為 class 元件新增 Ref

如果我們想包裝上面的 CustomTextInput,來模擬它掛載之後立即被點選的操作,我們可以使用 ref 來獲取這個自定義的 input 元件並手動呼叫它的 focusTextInput 方法:

class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  componentDidMount() {
    this.textInput.current.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}

class CustomTextInput extends React.Component {
  // ...
}

需要注意的是:僅在 CustomTextInput 宣告為 class 時才有效

Refs 與函式元件

預設情況下,我們不能在函式元件上使用 ref 屬性,因為它們沒有例項。也就是說我們自己定義的函式元件,當別人引用它並且想使用ref屬性,這種是無效的。
如果非要在函式元件中使用 ref,可以使用 forwardRef,或者將該元件轉化為 class 元件。

function MyFunctionComponent() {
  return <input />;
}
class App extends React.Component{
	constructor(props){
		super(porps);
		this.textInput = React.createRef();
	}
	render(){
		//ref是無效的
		return <MyFunctionComponent ref={this.textInput} />
	}
}

雖然不能在函式元件上使用ref,但是我們可以在函式元件內部使用ref,需要藉助useRef() 鉤子函式

function CustomTextInput(props) {
  // 這裡必須宣告 textInput,這樣 ref 才可以引用它
  const textInput = useRef(null);

  function handleClick() {
    textInput.current.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={textInput} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

Refs轉發

Ref 轉發是一項將 ref 自動地通過元件傳遞到其一子元件的技巧。對於大多數應用中的元件來說,這通常不是必需的。但其對某些元件,尤其是可重用的元件庫是很有用的。
下面的示例中,MyButton使用React.forwardRef來獲取傳遞給它的ref,然後轉發到它渲染的DOM button上。這樣使用MyButton的元件可以獲取到底層DOM節點button的ref,並在必要時訪問,就像直接使用DOM button一樣

const MyButton = React.forwardRef((props, ref) =>{
	(
		<button ref={ref} className="my-button">{props.children}</button>
	)
});

//可以直接獲取DOM button的ref
const ref = React.createRef();
<MyButton ref={ref}>click me</MyButton>
  • 上面說過,在函式元件上是不能使用ref的,那麼這裡卻使用了ref那麼是不是自相矛盾了呢?其實並不矛盾,細想:當我們在類元件或原生DOM元素上使用ref屬性時,那麼這個ref是直接與類元件或DOM元素繫結的,也就是說我們可以通過ref就能直接操作元件或者DOM元素。
  • 而在這個示例中我們在函式元件上使用了ref,但不同的是:這個ref繫結的並不是當前函式元件本身,而是函式元件的子元素button

下面簡單簡單描述一下上面案例的執行步驟:

  • 1、我們通過呼叫React.createRef()建立了一個ref並將其賦值給變數ref
  • 2、指定ref為JSX屬性,通過MyButton元件將其向下傳遞
  • 3、React 將ref作為引數傳遞給forwardRef函式,再通過該函式將其向下傳遞
  • 4、然後向下轉發該ref引數到button上,同時將其指定為button的JSX屬性
  • 5、當 ref 掛載完成,ref.current 將指向 < button> DOM 節點。
  • 6、最後我們就可以在外部直接訪問到元件內部的元素了

以上就是關於Refs的一些相關知識。
下一章節中我們將會繼續學習React進階中的高階元件