[React] コンポーネントを理解する！

### コンポーネント
:memo: Reactにおけるコンポーネントとは、関数であり、`JSX`（`ReactElement`）を返します。

```tsx
// サンプルコード
import React from 'react';

type Props = {
  message: string;
}

const SampleComponent: React.FC<Props> = ({message}) => {  
  return <h1>{message}</h1>
}

export default SampleComponent;
```

---

### props

`props`はコンポーネントに渡される引数です。
コンポーネントにデータを渡す際に利用されます。

以下の例は`ParentComponent`から`ChildComponent`呼び出し時に`greeting`属性を指定し、`props`から情報を取得しています。

**サンプルコード:**
```tsx
const ParentComponent = () => {
  return <ChildComponent greeting="Hello, World!" />;
}

const ChildComponent = ({greeting}) => {
  return <h1>{greeting}</h1>;
}
```

---

### コンポーネントの利用
コンポーネントを利用する場合、通常以下の流れとなります。
1. コンポーネントを定義
2. 定義したコンポーネントを`export`
3. 親コンポーネントで定義したコンポーネントを`import`し、呼び出す
（必要に応じて`Props`を渡す）

```tsx
// ChildComponent.tsx
import React from 'react';

type Props = {
  greeting: string;
}

export const ChildComponent: React.FC<Props> = ({greeting}) => {  
  return <h1>{greeting}</h1>;
}
```

```tsx
// App.tsx
import React from 'react';
import { ChildComponent } from './ChildComponent';

const App: React.FC = () => {
  return <ChildComponent greeting="Hello from App Component" />;
}

export default App;
```

---

### コンポーネントの子要素を受け取る
React 17までは、コンポーネント呼び出し時に指定された、子要素が`props`オブジェクトの`children`プロパティとして含まれていました。

React 18では、`children`が`props`に標準で含まれなくなりました。
コンポーネントで子要素を扱いたい場合は、`PropsWithChildren`を使用して子要素を扱うことを明示的に宣言する必要があります。

**サンプルコード:**
```tsx
import React, { PropsWithChildren } from 'react';

type Props = {
  title: string;
  folded?: boolean;
};

const Summary: React.FC<Props & PropsWithChildren> = ({ title, folded = false, children }) => {
  return (
    <details open={!folded}>
      <summary>{title}</summary>
      {children}
    </details>
  );
};

export default Summary;
```

---

### 値がtrueの場合は記述を省略できる
JSXでは、属性の値が`true`である場合、その値を省略して記述することができます。

**サンプルコード:**
```tsx
const MyComponent = () => {
  return <input type="checkbox" checked />;
}
```

---

### 組み込みコンポーネント
#### ユーザ定義コンポーネントの命名規則
`JSX`では、小文字で始まる名前のタグは組み込みコンポーネントとして解釈されます。
- `div`, `a`

大文字で始まる名前のタグはユーザ定義コンポーネントとして解釈されるため、カスタムコンポーネントは必ず大文字で始める必要があります。
- `MyComponent`

---

### JSX、HTMLでの属性の違い
`JSX`では、属性名が`HTML`の標準的な書き方から変更されている場合があります。
キャメルケースの使用や、特定の`HTML`属性名が`JavaScript`の予約語と競合するための変更が含まれます。

#### キャメルケースとして扱われる属性
`JSX`では、HTML属性の多くがキャメルケースで書かれる必要があります。これは`JavaScript`のプロパティアクセスの規則に従うためです。

**例:**
- `srcset` -> `srtSet`
- `tabindex` -> `tabIndex`

**サンプルコード:**
```jsx
<div tabIndex={0}>
  {/* コンテンツ */}
</div>
```

#### 属性名がHTMLと異なるもの
以下のHTML属性は、`JavaScript`の予約語と競合しているため、`JSX`では異なる名前で使用されます。

- `for` -> `htmlFor`
- `class` -> `className`

```tsx
<label htmlFor="myInput">Label</label>
<input id="myInput" className="inputClass" />
```

#### Booleanとして扱われる属性
JSXでは、以下の属性は明示的に`true`または`false`を指定しなくても`Boolean`として解釈されます。
- `disabled`
- `readOnly`
- `required`


そのため、値が`true`の場合は、以下のように記載することができます。
```tsx
<input disabled />
```

---

### value + defaultValue属性
JavaScript でフォームを操作しやすいように`JSX`では、`select`, `textarea`タグに`value`, `defaultValue`属性を指定できます。

```tsx
<textarea value={textareaValue} />

<select value={selectValue}>
  <option value="option1">Option 1</option>
  <option value="option2">Option 2</option>
</select>
```

#### value, defaultValueの使い分け
- デフォルト値を設定したい -> `defaultValue`
- デフォルト値を指定し、値をstateで管理したい -> `value`

※ `value`属性で値を指定したのに`state`管理を行わない場合、`eslint`で`warning`が発生するので注意

---

### key属性
`JSX`では、繰り返し処理で要素をレンダリングする際に`key`属性が必要です。
Reactの差分抽出エンジンが、`DOM`を一意に特定するためです。

`key`属性を指定していない以下のコードはwarningが発生します。
- `Missing "key" prop for element in iterator`

```tsx
const items = [{ id: 1, text: 'First item' }, { id: 2, text: 'Second item' }];

const ListComponent = () => {
  return (
    <ul>
      {items.map(item => (
        <li>{item.text}</li>
      ))}
    </ul>
  );
};
```

`key`属性を指定することでエラーが解消されます。
```tsx
const items = [{ id: 1, text: 'First item' }, { id: 2, text: 'Second item' }];

const ListComponent = () => {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
};
``` 

---

### [:memo: ライブラリ] propTypes

`propTypes`はコンポーネントのpropsの型を検証するために使用され、型が合わない場合には開発中に警告を表示してくれるライブラリです。

```tsx
import PropTypes from 'prop-types';

const Greeting = ({ name }) => {
  return <h1>Hello, {name}</h1>;
}

Greeting.propTypes = {
  name: PropTypes.string.isRequired
};

export default Greeting;
```

### まとめ
以上です。
個人用の備忘録用としてまとめておりますが、どなたかの役に立てたなら幸いです。