「button
や input
の型定義ってどうだっけ?」
作成するたびにググって確認しているので、いい加減覚えないと。
ということでアウトプットを兼ねて書き記しておきます。
//tsのバージョン
typeScript Version 4.6.4
せっかくなので、Reactでコンポーネントを作りながらやっていまきす。
今回のディレクトリ構成はひとまずこんな感じにしました。
後でしっかり読みたい記事はこちら : 私のフロントエンドディレクトリ構成・テスト観点 2022
App.tsx
App.tsxは、コンポーネントを並べるだけです。
import { useRef } from 'react';
import { Button } from './components/common/form/element/Button'
import { Input } from './components/common/form/element/Input'
import { CheckBox } from './components/common/form/element/CheckBox';
import { Select } from './components/common/form/element/Select';
import { TextArea } from './components/common/form/element/TextArea';
export const App = () => {
const handler = () => {
console.log("hello")
}
const fruits = [
{ id: 1, name: 'りんご' },
{ id: 2, name: 'バナナ' },
{ id: 3, name: 'メロン' },
]
const ref = useRef<HTMLButtonElement>(null!)
const catchRef = () => {
console.log(ref.current)
}
return (
<div className="App">
<button onClick={catchRef}>Buttonのref.current</button>
<Button
onClick={handler}
type='reset'
name='testButton'
className='resetButton'
ref={ref}
>
<span>次へ</span>
</Button>
<br />
<Input
onFocus={handler}
name='testInput'
className='inputText'
/>
<br />
<CheckBox
name="fruits"
defaultChecked={false}
className='checkBox'
/>
<br />
<Select
name="fruits"
className='checkBox'
option={fruits}
/>
<br />
<TextArea
onFocus={handler}
name='testInput'
className='textArea'
placeholder='ご要望'
/>
</div>
);
}
使う
ComponentProps
を用いて型を指定する時、refを含んでいるかを明確にするため
ComponentPropsWithoutRef
, ComponentPropsWithRef
を使用します。
結局 React のコンポーネントにはどうやって型をつければ良いのさ - 蛇足部分
Button component
HTMLxxxElement
は、HTMLElement
の詳細。
Buttonの場合は、 「HTMLElementの中のHTMLButtonElementだよ」
とジェネリクスで書く必要がある。
HTMLElementはこちら
import { ComponentPropsWithoutRef, forwardRef } from "react";
export const Button = forwardRef<
HTMLButtonElement,
ComponentPropsWithoutRef<"button">
>(function ButtonElement({ className, ...props }, ref) {
return (
// スプレット構文でまるっと渡す
<button {...props} ref={ref} />
);
});
Input component
Buttonコンポーネントとほぼ同じように書くことができる。
HTMLInputElement
と宣言するように!
import { ComponentPropsWithoutRef, forwardRef } from "react";
export const Input = forwardRef<
HTMLInputElement,
ComponentPropsWithoutRef<"input">
>(function InputElement({ className, ...props }, ref) {
return (
<input
type="text"
{...props}
ref={ref}
/>
);
});
TextArea component
Buttonコンポーネントとほぼ同じように書くことができる。
HTMLTextAreaElement
と宣言するように!
*今回は使っていませんが、自動的に高さが可変する react-textarea-autosize はおすすめです。
import { ComponentPropsWithoutRef, forwardRef } from "react";
export const Textarea = forwardRef<
HTMLTextAreaElement,
ComponentPropsWithoutRef<"textarea">
>(function TextareaElement({ className, ...props }, ref) {
return (
<textarea {...props} ref={ref}/>
);
});
CheckBox component
もうちょっと改良の余地があると思っています。
引き続き調べる。
type Props = {
name: string
defaultChecked: boolean
className: string
}
export const CheckBox = ({ ...props }: Props) => {
return <input type='checkbox' {...props} />
}
Select component
下記は簡略的な書き方。
こちらは合わせて HTMLSelectElement
についてもしっかり覚えておく必要がある。
React コンポーネントで入力フォームを作成する (1) 自力編
import { FC } from 'react';
type SelectType = JSX.IntrinsicElements["select"]
// こちらでもOK
// type Option = {
// option: {
// id: number
// name: string
// }[]
// }
// type Props = SelectType & Option
type Option = {
id: number
name: string
}
type OptionProps = {
option: Option[]
}
type Props = SelectType & OptionProps
export const Select: FC<Props> = ({ ...props }) => {
return (
<select {...props}>
{props.option.map((data) =>
<option key={data.id}>
{data.name}
</option>
)}
</select >
)
}
formで使用するElementは汎用的にしておきたいですよね。
覚えはじめは苦戦しましたが、1つ1つ理解していけばするすると入ってきました。
まだふわっとしている部分もありますが、これから固めていきますよ!!!!!