參考
如同我們在第一章節所學,DOM 提供了一個命令式 API,它讓我們可以呼叫元素上的函式來進行變更。一個我們可能需要從 Preact 元件存取命令式 DOM API 的範例是自動將焦點移至輸入元素。
autoFocus
屬性(或 autofocus
特性)可以用於在第一次呈現時將焦點移至輸入,然而在某些情況下,我們會希望在特定時間或回應特定事件時將焦點移至輸入。
對於這些需要我們直接與 DOM 元素互動的情況,我們可以使用稱為「ref」的功能。ref 是具有 current
屬性的純 JavaScript 物件,指向任何值。JavaScript 物件是透過參照傳遞的,這表示任何有權存取 ref 物件的函式都可以使用 current
屬性取得或設定其值。Preact 不會追蹤 ref 物件的變更,因此它們可以用於在呈現期間儲存資訊,然後任何有權存取 ref 物件的函式都可以稍後存取這些資訊。
我們可以看到在不呈現任何內容的情況下,ref 功能的直接使用方式如下
import { createRef } from 'preact'
// create a ref:
const ref = createRef('initial value')
// { current: 'initial value' }
// read a ref's current value:
ref.current === 'initial value'
// update a ref's current value:
ref.current = 'new value'
// pass refs around:
console.log(ref) // { current: 'new value' }
ref 在 Preact 中之所以有用,是因為可以在呈現期間將 ref 物件傳遞給虛擬 DOM 元素,而 Preact 會將 ref 的值(其 current
屬性)設定為對應的 HTML 元素。設定後,我們可以使用 ref 的目前值來存取和修改 HTML 元素
import { createRef } from 'preact';
// create a ref:
const input = createRef()
// pass the ref as a prop on a Virtual DOM element:
render(<input ref={input} />, document.body)
// access the associated DOM element:
input.current // an HTML <input> element
input.current.focus() // focus the input!
不建議全域性使用 createRef()
,因為多重呈現會覆寫 ref 的目前值。相反地,最好將 ref 儲存為類別屬性
import { createRef, Component } from 'preact';
export default class App extends Component {
input = createRef()
// this function runs after <App> is rendered
componentDidMount() {
// access the associated DOM element:
this.input.current.focus();
}
render() {
return <input ref={this.input} />
}
}
對於函式元件,useRef()
鉤子提供一個方便的方式來建立一個 ref,並在後續渲染中存取同一個 ref。以下範例也顯示如何使用 useEffect()
鉤子在元件渲染後呼叫回呼函式,其中 ref 的目前值會設定為 HTML 輸入元素
import { useRef, useEffect } from 'preact/hooks';
export default function App() {
// create or retrieve our ref: (hook slot 0)
const input = useRef()
// the callback here will run after <App> is rendered:
useEffect(() => {
// access the associated DOM element:
input.current.focus()
}, [])
return <input ref={input} />
}
請記住,ref 不僅限於儲存 DOM 元素。它們可以用於在元件渲染之間儲存資訊,而不會設定會導致額外渲染的狀態。我們將在後面的章節中看到一些用途。
試試看!
現在讓我們透過建立一個按鈕來實作,當按鈕被按一下時,會透過 ref 存取輸入欄位並將焦點移至該欄位。