React

@lit/react 套件提供了實用工具,可為 Web 元件建立 React 包裝元件,並從響應式控制器建立自訂 Hook。

React 元件包裝器可讓您在自訂元素上設定屬性(而不僅僅是屬性)、將 DOM 事件對應到 React 風格的回呼,並在 TypeScript 中啟用 JSX 的正確型別檢查。

這些包裝器針對兩個不同的受眾

  • Web 元件的使用者可以包裝元件和控制器,以便在自己的 React 專案中使用。
  • 元件的供應商可以發佈 React 包裝器,以便他們的 React 使用者擁有其元件的慣用版本。

React 已經可以渲染 Web 元件,因為自訂元素只是 HTML 元素,而且 React 知道如何渲染 HTML。但是 React 對於 HTML 元素做出了一些假設,這些假設並不總是適用於自訂元素,而且它以不同的方式對待小寫標籤名稱與大寫元件名稱,這可能會使自訂元素的使用比必要的更困難。

例如,React 假設所有 JSX 屬性都對應到 HTML 元素屬性,並且沒有提供設定屬性的方法。這使得很難將複雜的資料(如物件、陣列或函式)傳遞給 Web 元件。React 也假設所有 DOM 事件都有對應的「事件屬性」(onclickonmousemove 等),並使用它們而不是呼叫 addEventListener()。這表示為了正確使用更複雜的 Web 元件,您通常必須使用 ref() 和命令式程式碼。(如需關於 React Web 元件整合限制的更多資訊,請參閱Custom Elements Everywhere。)

React 正在努力解決這些問題,但在此期間,我們的包裝器會負責為您設定屬性和監聽事件。

@lit/react 套件提供了兩個主要的匯出

  • createComponent() 會建立一個 React 元件,該元件會「包裝」現有的 Web 元件。包裝器可讓您在元件上設定 Props,並將事件監聽器新增至元件,就像您對待任何其他 React 元件一樣。

  • useController() 可讓您將 Lit 響應式控制器當作 React Hook 使用。

createComponent() 函式會為自訂元素類別建立 React 元件包裝器。包裝器會正確地將 React props 傳遞給自訂元素所接受的屬性,並監聽自訂元素所觸發的事件。

匯入 React、自訂元素類別和 createComponent

定義 React 元件之後,您可以像使用任何其他 React 元件一樣使用它。

請在React 遊樂場範例中查看其運作方式。

createComponent 接受一個具有以下屬性的選項物件

  • tagName:自訂元素的標籤名稱。
  • elementClass:自訂元素類別。
  • react:匯入的 React 物件。這用於使用使用者提供的 React 建立包裝元件。這也可以是 preact-compat 的匯入。
  • events:一個物件,將事件處理常式屬性對應到自訂元素觸發的事件名稱。

使用 createComponent() 建立的元件子項會渲染到自訂元素的預設插槽。

若要將子項渲染到特定命名的插槽,可以新增標準的 slot 屬性。

由於 React 元件本身不是 HTML 元素,它們通常無法直接擁有 slot 屬性。若要渲染到命名的插槽,元件將需要使用具有 slot 屬性的容器元素進行包裝。如果包裝器元素干擾樣式設定(例如網格和彈性盒子配置),則給它一個 display: contents; 樣式(請參閱 MDN 以了解詳細資訊)將從渲染中移除容器,並且只渲染其子項。

React 插槽遊樂場範例中試用看看。

events 選項接受一個物件,該物件將 React 屬性名稱對應到事件名稱。當元件使用者傳遞具有其中一個事件屬性名稱的回呼屬性時,包裝器會將其新增為對應事件的事件處理常式。

雖然 React 屬性名稱可以隨您所欲,但建議的慣例是在事件名稱前面新增 on。這與 React 計劃如何實作自訂元素的事件支援一致。您也應該確保此屬性名稱不會與元素上的任何現有屬性衝突。

在 TypeScript 中,可以透過將事件名稱轉換為 EventName 公用程式型別來指定事件型別。這是一個很好的實務,如此一來,React 使用者會獲得其事件回呼最準確的型別。

EventName 型別是一個字串,它會將事件介面當作型別參數。在這裡,我們將 'my-event' 名稱轉換為 EventName<MyEvent>,以提供正確的事件型別

將事件名稱轉換為 EventName<MyEvent> 會使 React 元件具有一個接受 MyEvent 參數(而不是純 Event)的 onMyEvent 回呼屬性

在渲染期間,包裝器會從 React 接收 Props,並根據選項和自訂元素類別,變更某些 Props 的行為

  • 如果屬性名稱是自訂元素上的屬性(使用 in 檢查判斷),則包裝器會將元素上的該屬性設定為 Props 值
  • 如果屬性名稱是傳遞給 events 選項的事件名稱,則會將屬性值傳遞給 addEventListener(),並使用該事件的名稱。
  • 否則,該屬性會傳遞給 React 的 createElement() 以渲染為屬性。

屬性和事件都會在 componentDidMount()componentDidUpdate() 回呼中新增,因為元素必須已經由 React 實例化,才能存取它。

對於事件,createComponent() 接受一個 React 事件屬性名稱到自訂元素觸發的事件的對應。例如,傳遞 {onfoo: 'foo'} 表示當自訂元素觸發 foo 事件時,會呼叫透過名為 onfoo 的屬性傳遞的函式,並將事件當作引數傳遞。

響應式控制器允許開發人員掛鉤到元件的生命週期,以將與功能相關的狀態和行為捆綁在一起。它們在使用者案例和功能方面類似於 React Hook,但是是純 JavaScript 物件,而不是具有隱藏狀態的函式。

useController() 可讓您從響應式控制器建立 React Hook,以便在 Web 元件和 React 之間共享狀態和行為。

請參閱響應式控制器文件中的滑鼠控制器範例以了解其實作。

useController() 會為傳遞給它的控制器建立自訂主機物件,並透過使用 React Hook 來驅動控制器的生命週期。

  • useState() 用於儲存控制器的實例和 ReactControllerHost
  • Hook 主體和 useLayoutEffect() 回呼會盡可能地模擬 ReactiveElement 的生命週期。
  • ReactControllerHost 會實作 addController(),以便控制器組合有效,並且會正確呼叫巢狀控制器的生命週期。
  • ReactControllerHost 也會透過呼叫 useState() 設定器來實作 requestUpdate(),以便控制器可以導致其主機元件重新渲染。