Skip to main content

[ReactDoc] Refs and the DOM

資料來源:Refs and the Dom @ React Docs

重要觀念#

❗ React 會在 component mount 時將參照的 DOM 元素放到 current 屬性中;在 componentDidMountcomponentDidUpdate 之前更新 ref;並且在 unmount 時將其設為 null

❗ 因為 ref 實際上是取得一個 DOM 參照出來的 HTML 元素 ​(已經不是原本的 HTML 元素),因此最好拿來取值就好如果要註冊事件的話或設值,要註冊在原本的 HTML 元素上,而不是 ref

使用時機#

  • 用來控制元素的 focus, text selection 或 media 播放事件
  • 用來觸發重要的動畫
  • 和第三方的 DOM 套件整合

基本使用#

建立 Refs#

Refs 可以使用 React.createRef() 來建立,並且透過在 React 的 DOM 元素上使用 ref 屬性來產生連結:

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

使用 Refs#

可以透過 ref 中的 current 來取得該 DOM 節點(node)的參照:

const node = this.myRef.current;

根據 node 類型的不同,current 會得到不同的內容:

  • ref 使用在一般的 HTML 元素時,current 會是該 DOM 元素。
  • ref 使用在 React 的類別元件(class component)上時,current 會是該元件的實例。
  • 除非是要使用 React.forwardRef,否則你應該不會在 function component 上 ref 屬性。

生命週期:

  • React 會在元件掛載(mount)時為 current 屬性設定內容,當它解除掛載(unmount)時則把內容設為 null

  • ref 會在 componentDidMountcomponentDidUpdate 之前更新。

在 Functional Component 使用 Refs#

一般來說,因為 function component 中並沒有 this 實例,因此通常是無法使用 ref 的,例如:

/**
* 這是錯誤用法
**/
const Foo = () => {/* ... */};
const App = () => {
const fooRef = useRef(null);
return (
{/* 不能這樣用 */}
<Foo rel={fooRef} />
)
}

但你是可以在 functional component 中使用 ref 的。若想要在 functional component 中使用 ref,可以在該函式 return 前建立 refs

function CustomTextInput(props) {
let 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>
);
}

使用 Callback Refs#

React 也支援另一種設定 refs 的方式,稱作回呼參照(callback refs)

這種方式不需要先透過 createRef() 來建立 ref,而是直接代入一個函式,這個函式所代入的參數可以得到指稱的 HTML DOM 元素或 React 的元件實例,得到的這個物件可以存起來在其他地方取用。

React 一樣會在元件掛載(mounts)時呼叫此 callback ref(即,this.setTextInputRef);在元件卸載(unmount)時把此 ref 的值設為 null;並在 componentDidMount 或 componentDidUpdate 時確保 Ref 會被更新。

class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 利用 callback Ref 把取得的 element 保存在 textInputRef 的變數中
this.textInputRef = null;
// Callback Refs
this.setTextInputRef = (element) => {
this.textInputRef = element;
};
this.focusTextInput = () => {
if (this.textInputRef) this.textInputRef.focus();
};
}
componentDidMount() {
// autofocus the input on mount
this.focusTextInput();
}
render() {
return (
<div>
<input type="text" ref={this.setTextInputRef} />
</div>
);
}
}

你同樣可以利用這個方式來達到類似 forwardRef 的效果:

function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return <CustomTextInput inputRef={(el) => (this.inputElement = el)} />;
}
}

參考#

Last updated on