ReactJS - Refs 和 DOM

您好,未來的 React 開發者!今天,我們將深入一個令人興奮的主題,這將幫助您在 React 應用程序中直接與 DOM 元素交互。請坐好,因為我們即將探索 Refs 和 DOM 的世界!

ReactJS - Refs and the DOM

Refs 是什麼?

在我們深入細節之前,讓我們先了解 Refs 是什麼。在 React 中,"Ref" 是 "reference" 的縮寫。它就像給一個特定的元素貼上名標籤,這樣您可以稍後輕鬆找到它。想像您在一個大派對上,您想跟踪您最好的朋友。您可能會給他們一頂特殊的帽子或獨特的名標籤。這基本上就是 React 中 Ref 的作用 - 它幫助您跟踪特定的元素。

我們為什麼需要 Refs?

您可能會想,"我們為什麼不能直接使用常规的 JavaScript 選擇元素?" 在 React 中,我們試圖避免直接操作 DOM(文件對象模型),因為 React 有其自己的高效更新 UI 的方式。然而,有時候我們需要脫離 React 的聲明性範式,直接與 DOM 元素工作。這就是 Refs 派上用場的地方!

使用 createRef() 創建 Refs

讓我們從看我們如何在 React 中創建一個 Ref 開始。我們使用一個名為 createRef() 的方法。

createRef 方法的簽名

createRef() 的簽名非常簡單:

React.createRef()

就這樣!沒有參數,沒有複雜性。它返回一個具有單一屬性的普通對象:current。最初,這個 current 屬性被設置為 null

讓我們看一個例子:

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

render() {
return <div ref={this.myRef} />;
}
}

在這個例子中,我們在構造函數中創建一個 Ref,並將其分配給 this.myRef。然後在 render 方法中,我們使用 ref 屬性將這個 Ref 附加到一個 div 元素。

應用 Ref

現在我們已經創建了我們的 Ref,讓我們看看我們如何使用它。有幾種方法可以應用 Ref:

1. 在 DOM 元素上使用 Refs

最常見的使用案例是將 Ref 应用到 DOM 元素:

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

componentDidMount() {
this.inputRef.current.focus();
}

render() {
return <input ref={this.inputRef} />;
}
}

在這個例子中,我們為輸入元素創建了一個 Ref。在組件挂载後,我們使用 Ref 自動聚焦到輸入框。Ref 的 current 屬性給我們提供了實際的 DOM 节點的訪問權。

2. 在類組件上使用 Refs

您也可以在類組件上使用 Refs:

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

componentDidUpdate() {
const node = this.listRef.current;
node.scrollToItem(0);
}

render() {
return <MyListComponent ref={this.listRef} />;
}
}

在這種情況下,this.listRef.current 將指向 MyListComponent 類的實例。

3. 在函數組件上使用 Refs

函數組件不能直接被賦予 Refs,但您可以使用 forwardRef 函數來傳遞 Refs:

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

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

render() {
return <FancyButton ref={this.buttonRef}>點我!</FancyButton>;
}
}

在這個例子中,FancyButton 使用 forwardRef 將 Ref 透傳到實際的按鈕元素。

createRef 的使用案例

現在我們知道如何創建和應用 Refs,讓我們看看一些常見的使用案例:

1. 管理焦點、文本選擇或媒體播放

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

focusTextInput = () => {
this.inputRef.current.focus();
}

render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.focusTextInput}>聚焦輸入框</button>
</div>
);
}
}

這個組件讓我們可以在點擊按鈕時程序化地聚焦輸入框。

2. 觸發命令式動畫

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

animate = () => {
this.elementRef.current.classList.add('animated');
}

render() {
return (
<div>
<div ref={this.elementRef}>動畫我!</div>
<button onClick={this.animate}>開始動畫</button>
</div>
);
}
}

在這裡,我們使用 Ref 添加一個 CSS 類到元素,觸發動畫。

3. 與第三方 DOM 库集成

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

componentDidMount() {
const mapLibrary = new FancyMapLibrary();
mapLibrary.createMap(this.mapRef.current);
}

render() {
return <div ref={this.mapRef} style={{width: '100%', height: '400px'}} />;
}
}

在這個例子中,我們使用 Ref 給第三方地圖庫訪問一個 DOM 節點,它可以在其中渲染地圖。

結論

Refs 是 React 中的強大工具,它們讓我們在必要時脫離聲明性範式。它們提供了一種直接訪問 DOM 節點或 React 元素的方式。然而,使用 Refs 應該謹慎。在大多數情況下,您可以通过 React 的聲明式 API 实现您需要的。但當您确实需要那麼一點額外的控制時,Refs 就會派上用場!

記住,能力越強,責任越大。謹慎使用 Refs,您的 React 應用程序會感謝您!

這裡是一個我們討論過的方法的快速參考表:

方法 描述 示例
React.createRef() 創建一個 ref 對象 this.myRef = React.createRef();
ref 屬性 將一個 ref 附加到 React 元素 <div ref={this.myRef} />
forwardRef 讓函數組件能夠接收 refs const FancyButton = React.forwardRef((props, ref) => ...)

開心編程,願您的 Refs 永遠是最新的!

Credits: Image by storyset