淺談 React 中的 ref 和 useRef
原文作者:Joel Adewole
原文地址:https://refine.dev/blog/react-useref-hook-and-ref/
翻譯:一川
在各種 JavaScript
庫和框架中,React
因其開發人員友好性和支持性而得到認可。
大多數開發人員發現 React
非常舒適且可擴展,因爲它提供了鉤子。鉤子是 React
附帶的內置 API,允許開發人員與 React
的狀態和生命週期功能進行交互。鉤子在類內部不起作用,因此它們只能在功能組件中使用。開發人員還可以決定創建自定義鉤子。
React
比大多數 UI 庫更能讓你重新思考設計標準,允許開發人員自定義 UI 組件,例如使用 React
和 JSX
的抽象機制而不是典型的 DOM 規範創建視圖。
在本文中,我們將討論 React 鉤子函數 useRef
,使用 ref
訪問 DOM 以及 ref
和 useRef
之間的區別。
什麼是 useRef?
React 中包含的各種鉤子之一是 useRef
鉤子; 它用於引用功能組件中的對象,並在重新渲染之間保留引用對象的狀態。
useRef
有一個名爲 “current
” 的屬性,用於隨時檢索引用對象的值,同時還接受初始值作爲參數。您可以通過更新 current
值來更改引用對象的值。
以下是創建引用對象的方法:
import { useRef } from ‘react’
const myComponent = () => {
const refObj = useRef(initialValue)
return (
//…
)
}
在上面的代碼片段中,我們有一個要在應用程序中引用的對象 refObj
,要訪問值或更新值,我們可以像這樣調用 current
該屬性:
// inside a function
const handleRefUpdate = () => {
// accessing the referenced object’s value
const value = refObj.current
// updating the referenced object’s value
refObj.current = newValue
}
您應該注意:
-
引用對象的值在重新渲染之間保持不變。
-
更新引用對象的值不會觸發重新呈現。
使用 ref 訪問 DOM 元素
請記住,DOM
元素也是對象,我們可以使用useRef
引用它們。但是現在,我們需要利用另一個名爲 ref
。
ref
是一個 HTML
屬性,它將引用的對象分配給 DOM
元素。讓我們看看這是如何工作的:
import {useRef} from ‘react’
const myComponent = () => {
const elementRef = useRef()
return (
<input ref={elementRef} type=”text” />
)
}
在上面的代碼片段中,我們創建了一個新的引用對象,elementRef
並使用屬性 ref
將其分配給輸入標記。我們可以訪問輸入標籤的值並像這樣更新值:
const handleInput = () => {
//accessing the input element value
const textValue = elementRef.current.value
// update the input element value
elementRef.current.value = “Hello World”
}
Ref 和 useRef 之間的區別
既然我們瞭解了useRef
和Ref
工作方式及它們的差異,讓我們看看如何在實際應用程序中使用它們。例如,我們希望爲彈出窗口實現一個點擊離開事件偵聽器。我們可以利用ref
訪問彈出窗口的 DOM 元素,並在彈出窗口外單擊時進行偵聽。
在你的 react 應用中,你可以創建一個名爲 “hooks
” 的文件夾,這個文件夾將包含自定義鉤子。
在文件夾中創建一個新文件 useClickAway
,並在文件中輸入以下代碼:
import React, { useEffect} from 'react'
export default function useClickAway(ref: any, callback: Function) {
useEffect(() => {
function handleClickAway(event: any) {
if (ref.current && !ref.current.contains(event.target)) {
callback();
}
}
document.addEventListener("mousedown", handleClickAway);
return () => {
document.removeEventListener("mousedown", handleClickAway);
};
}, [ref]);
};
在上面的代碼片段中,我們創建了一個接受引用對象作爲 ref
和回調函數的自定義鉤子,然後我們執行了一個事件偵聽器來檢查何時單擊鼠標,如果單擊不在當前 ref
上,則我們觸發回調函數。
以下是產品頁面上自定義掛鉤的實現:
import React, { useRef } from "react";
//.. Other importations
export default function Storefront() {
const targetElement = useRef(null)
const alertClickAway = () => {
alert("Clicked outside product 1")
}
useClickAway(targetElement, alertClickAway)
//.. Other functions
return (
{//.. Other parts of the application}
<div class>
<div class ref={targetElement}>
<img src="https://i.postimg.cc/G207QNV7/image.png" alt="Product 1" />
<p>iWatch Series 6</p>
<div class>
<button>
<img src="https://api.iconify.design/flat-color-icons:like.svg?color=%23888888" alt="like" />
</button>
<button>
<img
src="https://api.iconify.design/icon-park:buy.svg?color=%23888888"
alt="add" />
</button>
</div>
</div>
)
}
在上面的代碼片段中,我們有一個店面組件,我們在其中導入了自定義鉤子,然後我們創建了一個新的引用對象 targetElement
並將其分配給產品庫中的 div
,然後我們創建了一個回調函數useClickAway
,以便在使用ref
在產品項外部單擊鼠標時發出警報 targetElement
。
現在讓我們看看輸出:
Ref 和 useRef 的使用案例
你現在對什麼是ref
以及useRef
,以及它們的使用有了一定的瞭解。ref
和useRef
兩者都很容易被濫用,會造成使用開銷比較大。現在你可能需要考慮的是何時使用,以及如何儘可能避免使用。
以下是參考的一些用途:
-
與輸入元素交互:通過使用
refs
可以訪問輸入元素並執行焦點、更改跟蹤或自動完成等功能。 -
與第三方 UI 庫交互:
ref
可用於與第三方 UI 庫創建的元素進行交互,這些元素使用標準 DOM 方法訪問可能很棘手。例如,如果您使用第三方庫生成滑塊,則可以使用ref
訪問滑塊的 DOM 元素,而無需被告知滑塊庫源代碼的結構。 -
媒體播放:您還可以使用
refs
訪問圖像、音頻或視頻等媒體資產,並與它們的呈現方式進行交互。例如,當元素進入視口時自動播放視頻或延遲加載圖像。 -
複雜動畫觸發:傳統上,
CSS
關鍵幀或超時用於確定何時啓動動畫。在某些情況下(可能更復雜),您可以使用refs
來觀察 DOM 元素並確定何時開始動畫。
在某些情況下(如下所示),不應使用引用:
-
聲明性案例:即使在使用
refs
的簡單解決方案的情況下,也無需編寫更昂貴的代碼來執行相同的任務。例如,使用條件渲染來隱藏或顯示 DOM 元素而不是ref
。 -
影響狀態的元素:有時,使用
refs
的概念非常有趣,以至於您忽略了對元素所做的修改對應用程序生命週期的影響。您應該記住,對ref
的更改不會導致重新渲染,並且ref
在渲染中保持其對象的值。因此,建議避免在狀態更改需要觸發重新渲染的情況下使用ref
。 -
訪問功能組件:不應被誤認爲功能組件的 DOM 元素可以使用
Ref
屬性進行引用。因爲,與類組件或 DOM 元素不同,功能組件沒有實例。例如:
import {useRef} from ‘react’
const FunctionalComponent = () => {
return (
<h1>Hello World<>
)
}
const myComponent = () => {
const elementRef = useRef()
return (
<FunctionalComponent ref={elementRef} />
)
}
由於組件 FunctionalComponent
沒有實例,因此上述代碼片段中的 ref
將不起作用。相反,我們可以將其轉換爲FunctionalComponent
類組件或在 FunctionalComponent
組件的 forwardRef
中使用。
結論
在本文中,我們討論瞭如何使用 useRef
鉤子創建引用,該鉤子採用初始值並修改引用對象的 “current
” 屬性的值以更新其值。
我們看到了如何將 “current
” 值與 “ref
” 一起使用來訪問 DOM 元素並與其屬互。
我們將介紹如何創建一個接受引用 DOM 元素的自定義鉤子和一個回調函數,以便在應用程序中使用 “ref
” 和 “useRef
” 來觀察 DOM 元素上的單擊事件。
此外,我們還討論了 “ref
” 和 “useRef
” 的用例,何時使用它們,何時不使用它們。
在瞭解了ref
以及useRef
如何在不重新渲染父組件的情況下跟蹤和更新可變值之後,您可以通過查看Refs
和 useRefs
的 React
的相關官方文檔,來探索更多關於它們的信息或瞭解更多信息,甚至嘗試其他 React
鉤子。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/pHs8w_eEsYj7k9XydBNr4Q