昨天,我們終於將 Todo List 的功能完成,今天開始,我們要來探索一些先前沒有機會用到的小技巧以及觀念。
在 Todo List 中,所有的 <input> 都是獨立的,對於 React 開發者來說,當有多個地方使用到 <input> 或 <button> ... 等時,我們會習慣將它直接作為一個元件,藉由傳入不同的 props,讓這個元件可以重複利用於不同的情境下。
今天我們以 <input> 來探索在 React 中使用 TypeScript 的小技巧。
首先,創建一個 Input 元件:
export default function Input() {
return (
<div>
<label htmlFor=''></label>
<input id='' />
</div>
)
}
label 的內容以及 id 我們會透過 props 傳入,因此在這邊需要為 props 定義型別:
type InputProps = {
label: string
id: string
}
export default function Input({ label, id }: InputProps) {
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} />
</div>
)
}
回到 App.tsx 並匯入 Input 元件,我們可以透過傳遞不同的資訊,創建內容不同的 Input:
import './App.css'
import Input from './components/Input'
function App() {
return (
<main>
<Input id='account' label='Account' />
<Input id='password' label='Password' />
</main>
)
}
export default App
目前我們僅僅是傳遞 id 以及 label 給 Input 元件,若我們需要傳入其他 <input> 可以使用的屬性呢?
常見的寫法是運用展開運算子:
export default function Input({ label, id, ...props }: InputProps) {
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} {...props} />
</div>
)
}
預估達到的效果是可以對 Input 元件傳入其他屬性,像是 type:
function App() {
return (
<main>
<Input id='account' label='Account' type='text' />
<Input id='password' label='Password' type='password' />
</main>
)
}
但這時候會收到錯誤訊息:
這是因為我們在 InputProps 中只定義了 id 與 label 的型別,並沒有為 type 定義型別,在這邊我們會使用到 Day08 所介紹的合併型別,合併我們指定的型別 (id & label) 以及 <input> 所有內建方法、屬性的型別。
而 React 已經幫我們內建好了這個型別,也就是 ComponentPropsWithoutRef。
合併 ComponentPropsWithoutRef 型別,並於泛型參數內傳入 input,告知 React 我們要使用的是 input 這個元素:
import { ComponentPropsWithoutRef } from 'react'
type InputProps = {
label: string
id: string
} & ComponentPropsWithoutRef<'input'>
export default function Input({ label, id, ...props }: InputProps) {
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} {...props} />
</div>
)
}
ComponentPropsWithRef 與 ComponentPropsWithoutRef 的差別僅在於接收的 props 是否包含 ref,適合用於使用 forwardRef 時,而我們目前的範例不需要傳入 ref,所以選擇使用 ComponentPropsWithoutRef。
打開瀏覽器,前往 http://localhost:5173/,你可以看見 password 欄位的 type 已經正確指定為 password 的形式。