React TypeScript useEffectについて

 ReactとTypeScriptの学習のために簡単なタスク管理アプリを開発。
 useEffectについて気になったため調べてメモで残す。

## useEffectとは
 useEffect は Reactのフック（Hooks） の1つで、副作用（Side Effects） を処理するために使用されます。副作用とは、コンポーネントのレンダリング以外で行う必要のある処理のことを指します。

Reactコンポーネントは基本的に「UIを状態に基づいて描画する」ことに特化していますが、時には以下のような処理が必要になることがあります：

### 副作用の例
* データ取得（APIリクエスト）
サーバーからデータを取得して表示する。
* ブラウザAPIの利用
ローカルストレージからのデータ取得・保存。
* タイマーやイベントリスナーの登録
コンポーネントが表示されたときにタイマーを開始する。
* DOMの操作
特定の要素にフォーカスを当てる。

これらの処理を、useEffect を使って適切なタイミングで実行します

## 今回の対象のtsxファイル

```typescript:App.tsx
import React, { useState, useEffect } from 'react';
import TaskList from './components/TaskList.tsx';
import TaskForm from './components/TaskForm.tsx';
import { Task } from './types/task.ts';

const App: React.FC = () => {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [filter, setFilter] = useState<'all' | 'completed' | 'incomplete'>('all');

  // ローカルストレージからタスクを取得
  useEffect(() => {
    const storedTasks = localStorage.getItem('tasks');
    if (storedTasks) {
      setTasks(JSON.parse(storedTasks));
    }
  }, []);

  // タスクをローカルストレージに保存
  useEffect(() => {
    localStorage.setItem('tasks', JSON.stringify(tasks));
  }, [tasks]);

  // タスクを追加
  const addTask = (title: string) => {
    const newTask: Task = { id: tasks.length + 1, title, completed: false };
    setTasks([...tasks, newTask]);
  };

  // タスクの完了状態を切り替え
  const toggleTask = (id: number) => {
    setTasks(tasks.map(task => task.id === id ? { ...task, completed: !task.completed } : task));
  };

  // タスクを削除
  const deleteTask = (id: number) => {
    setTasks(tasks.filter(task => task.id !== id));
  };

  // フィルタリングされたタスク
  const filteredTasks = tasks.filter(task => {
    if (filter === 'completed') return task.completed;
    if (filter === 'incomplete') return !task.completed;
    return true; // 'all'
  });

  return (
    <div>
      <h1>Task Manager</h1>
      <TaskForm addTask={addTask} />

      {/* フィルターボタン */}
      <div>
        <button onClick={() => setFilter('all')}>All</button>
        <button onClick={() => setFilter('completed')}>Completed</button>
        <button onClick={() => setFilter('incomplete')}>Incomplete</button>
      </div>

      {/* フィルタリングされたタスクを表示 */}
      <TaskList tasks={filteredTasks} toggleTask={toggleTask} deleteTask={deleteTask} />
    </div>
  );
};

export default App;

```

## 1. useEffectの基本構文

```typescript:App.tsx
useEffect(() => {
  // 副作用の処理
}, [依存配列]);
```
第1引数: 実行する処理（コールバック関数）。
第2引数（依存配列）: useEffectの実行条件を決定する配列。
## 2. 実行されるタイミング
useEffect が実行されるタイミングは、依存配列 によって異なります。

### (1) 依存配列が空（[]）
```typescript:App.tsx
useEffect(() => {
  console.log("初回レンダリング時のみ実行される");
}, []);
```
実行タイミング:
コンポーネントの初回レンダリング時のみ実行されます。
状態やプロパティが変更されても再実行されません。
### (2) 特定の依存変数が指定されている場合（[変数1, 変数2]）
```typescript:App.tsx
useEffect(() => {
  console.log("依存変数が変更された時に実行される");
}, [変数1, 変数2]);
```
実行タイミング:
コンポーネントの初回レンダリング時。
変数1 または 変数2 の値が変更された時。
例:
依存配列に tasks が指定されている場合：
```typescript:App.tsx
useEffect(() => {
  console.log("tasksが変更されました！");
}, [tasks]);
```
tasks の状態が更新されるたびに、このuseEffectが実行されます。
### (3) 依存配列が指定されていない場合（省略）
```typescript:App.tsx
useEffect(() => {
  console.log("毎回レンダリング後に実行される");
});
```
実行タイミング:
コンポーネントの初回レンダリング時。
すべてのレンダリング後に毎回実行されます。
注意:
状態やプロパティが変更されるたびに再レンダリングが発生し、その後このuseEffectも実行されるため、無限ループの原因になる可能性があります。