前兩篇已經談了 Web Component 套用到三大框架其中兩個框架 Angular
、Vue
的方法。
今天要介紹的是 Web Component 套用到 React
框架的方法。
而 React 應該算是三大框架中套用 Web Component 相對不友善的框架,接下來就跟著實作來看看吧!
今天使用密碼確認欄來當作要示範的案例。
表格內容有:
npm create vite@latest wc-input-react -- --template react
un-custom-input
npm install un-custom-input
src/main.ts
或 main.js
載入自訂元件import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import "un-custom-input";
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
4.在 App.jsx
中加入自訂元件,看看是否有出現
import './App.css'
function App() {
return (
<>
<un-custom-input></un-custom-input>
</>
)
}
export default App
和前面兩個框架一樣,都正常出現了自訂元件!
function App() {
return (
<>
<form className="form">
<div className="input-container">
<label>密碼</label>
<un-custom-input
type={'password'}
placeholder={'請輸入密碼'}
minLength={8}
pattern="^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,}$"
pattern-message={'英數混合,至少需要一個大寫英文'}
required={true}
>
</un-custom-input>
</div>
<div className="input-container">
<label>確認密碼</label>
<un-custom-input
type={'password'}
placeholder={'請確認密碼'}
required={true}
>
</un-custom-input>
</div>
</form>
</>
)
}
樣式一樣使用前一篇 angular 的 style! 詳見:Day 24
在前面介紹的 Angular 以及 Vue 都可以從 template 監聽到自訂元件的事件,但是 React 在事件的監聽上,就會比較麻煩一點。
如果你是使用 React 最為前端框架的使用者,相信你一定很清楚,React 是一個高度封裝、單向資料流的框架。
React 的核心是 Virtual DOM
,也就是會將 UI 的狀態保存在 Virtual DOM 中,然後根據狀態差異去更新實體的 DOM,在資料的交流上,也相當依賴 React 的狀態管理以及事件處理,所以當 React 遇到了使用 Shadow DOM 的 Web Component 可能就會遇到事件傳遞的問題。
事件不相容:
React 的 props 與事件機制是使用合成事件(Synthetic Events)來統一處理,像是 onClick
是綁定在 React 的 Virtual DOM 上,而不是直接綁定在原生 DOM 元素上。
Web Component 觸發的事件在 Shadow DOM 中,不一定會冒泡到 React 的事件系統中,所以 React 不會自動捕捉這些事件。
狀態同步問題:
Web Component 因為使用了 Shadow DOM
的關係,封裝了自己的 DOM 樹,使 React 無法直接操作或自動知道 Shadow DOM 中的變化,所以有可能導致 React 的狀態更新和 Web Component 的行為不一致的問題產生。
由於 React 不會自動傳遞非 HTML 原生的屬性也不會自動幫我們綁定自訂事件,所以就需要進行手動綁定
。
相信你看到上面這些問題,心裡也會開始覺得 React 真是相較其他兩位稍微不友善啊 (❍ᴥ❍ʋ)!
我們需要使用到 ref
+ useRef
,去取得元件 DOM 元素,利用 useEffect
手動將事件綁定上去。
再依據元件的邏輯使用 useEffect
確認兩個欄位的值是否一樣。
先修改 html 結構,加上 ref
。
<form className="form">
<div className="input-container">
<label>密碼</label>
<un-custom-input
ref={passwordRef}
type={'password'}
placeholder={'請輸入密碼'}
minLength={8}
pattern="^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,}$"
pattern-message={'英數混合,至少需要一個大寫英文'}
required={true}
>
</un-custom-input>
</div>
<div className="input-container">
<label>確認密碼</label>
<un-custom-input
ref={confirmRef}
type={'password'}
placeholder={'請確認密碼'}
required={true}
>
</un-custom-input>
</div>
</form>
使用 useRef
取得 DOM 的實例,並且利用 useState
記錄欄位的值,再利用 useEffect
綁定事件以及加入邏輯判斷:
function App() {
// 加入 ref 取得物件的 DOM 實例
const passwordRef = useRef(null);
const confirmRef = useRef(null);
// 使用 useState 寫入欄位中的值
const [password, setPassword] = useState('');
const [confirm, setConfirm] = useState('');
// 使用 useEffect 手動綁定自訂元件的自訂事件
useEffect(() => {
const passwordEl = passwordRef.current;
const confirmPasswordEl = confirmRef.current;
const handlePasswordChange = (e) => {
setPassword(e.detail.value);
};
const handleConfirmChange = (e) => {
setConfirm(e.detail.value);
};
// 綁定 Web Component 的事件
passwordEl.addEventListener('value-changed', handlePasswordChange);
confirmPasswordEl.addEventListener('value-changed', handleConfirmChange);
return () => {
passwordEl.removeEventListener('value-changed', handlePasswordChange);
confirmPasswordEl.removeEventListener('value-changed', handleConfirmChange);
};
}, []);
// 使用 useEffect 加入欄位的相關邏輯判斷
useEffect(() => {
if (confirm && password !== confirm) {
confirmRef.current.setCustomError('密碼不相符');
} else {
confirmRef.current.setCustomError('');
}
}, [password, confirm]);
return (//...略)
}
那麼現在,你就可以看見監聽到自訂事件,並且也加入了我們的驗證邏輯囉。
恭喜,三大框架的套用方式你都淺淺的學完了~
但是其實三大框架在套用時,還有其他可以更深入的地方,就要請大家實作中慢慢挖掘了(我也是持續在挖掘中)。
(“ ̄▽ ̄)-o█ █o-( ̄▽ ̄”)/