Reactのtodoリスト、localstrage使用

Reactで3ページ構成のlacalStorageを使用したTodoアプリを作ってみて
細かい機能をまとめようと書いてみました

# lacalStorageとは
ローカルストレージは、キーと値の形式でデータを保存するブラウザAPIの一部で、ページを再読み込みしてもデータが保持されるのが特徴です。

# 基本ステップ

```javascript
//値を保存する localStorage.setItem(key, value)を使用して、値をローカルストレージに保存します。
localStorage.setItem("username", "Takasuki");

// 値を取得する localStorage.getItem(key)で、保存された値を取得します。
const username = localStorage.getItem("username");
console.log(username); // "Tokumei"

//値を削除する localStorage.removeItem(key)で特定のキーを削除します。
localStorage.removeItem("username");

// すべてのデータをクリアする 全てのデータを削除するにはlocalStorage.clear()を使います。
localStorage.clear();
```

# 実際の使用

## Todoリストに追加の実装

まず定数を設定してローカルストレージの準備
```javascript
const navigate = useNavigate();
const handleAddTask = (newTask) => {
    const storedTasks = JSON.parse(localStorage.getItem('tasks')) || [];
    const updatedTasks = [...storedTasks, { id: storedTasks.length + 1, ...newTask }];
    
    localStorage.setItem('tasks', JSON.stringify(updatedTasks));
    navigate('/');
  };
```

作成した関数を設定
ついでに内容をコンポーネントにTaskFormを作成して引っ張ってくる

```javascript
import TaskForm from '../components/TaskForm';
  return (
      <div className="w-full max-w-lg bg-white shadow-md rounded-lg p-6">
        <TaskForm onAddTask={handleAddTask} />
      </div>
  );
  ```

  components/TaskFormに以下を記述してもってこれるように

  ```javascript
  import React, { useState } from 'react';

const TaskForm = ({ onAddTask }) => {
  const [title, setTitle] = useState('');
  const [description, setDescription] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!title.trim() || !description.trim()) return;

    onAddTask({ title, description });
    setTitle('');
    setDescription('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <div className='flex justify-between'>
        <label >タイトル</label>
        <input
          type="text"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          required
          className='border w-2/3'
        />
      </div>
      <div className='flex justify-between'>
        <label>詳細</label>
        <input
          type="text"
          value={description}
          onChange={(e) => setDescription(e.target.value)}
          required
          className=' border w-2/3'
        />
      </div>
      <button type="submit" className=' block mx-auto' >タスクの追加</button>
    </form>
  );
};

export default TaskForm;
```

これで追加ができるはずです

## 一覧の表示

Home画面より一覧表示を設定、詳細をcomponents/TaskListより記述して引っ張ってきてます
reactのルートについては別途記入します

```javascript
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import TaskList from "../components/TaskList";

  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const storedTasks = JSON.parse(localStorage.getItem("tasks")) || [];
    setTasks(storedTasks);
  }, []);

  return (
    <div className="min-h-screen bg-gray-100 flex flex-col items-center p-6">
      <h1 className="text-3xl font-bold text-gray-800 mb-6">To-Do リスト</h1>

      <div className="w-full max-w-2xl bg-white shadow-md rounded-lg p-4">
        <TaskList tasks={tasks} />
      </div>

      <Link
        to="/add"
        className="mt-6 px-6 py-3 bg-blue-500 text-white font-semibold rounded-lg shadow hover:bg-blue-600 transition"
      >
        タスクを追加
      </Link>
    </div>
  );
};

export default Home;
```

マップ構文より順々にtasksからidとdescriptonを引っ張ってこれるようにしてます
```javascript
import React from 'react';
import { Link } from 'react-router-dom';

const TaskList = ({ tasks }) => {
  return (
    <div>
      <h2>Task List</h2>
      {tasks.map((task) => (
        <div key={task.id}>
          <Link to={`/task/${task.id}`}>
            <h3>{task.title}</h3>
          </Link>
          <p>{task.description}</p>
        </div>
      ))}
    </div>
  );
};

export default TaskList;
```

## 削除機能

詳細ページで削除機能を入れてみました

```javascript
import React, { useEffect, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import TaskDetail from '../components/TaskDetail';

const TaskDetailPage = () => {
  const { id } = useParams();
  const navigate = useNavigate();
  const [task, setTask] = useState(null);

  useEffect(() => {
    const storedTasks = JSON.parse(localStorage.getItem('tasks')) || [];
    const foundTask = storedTasks.find((t) => t.id === Number(id));
    setTask(foundTask);
  }, [id]);

  // タスク削除関数
  const handleDeleteTask = () => {
    const storedTasks = JSON.parse(localStorage.getItem('tasks')) || [];
    const updatedTasks = storedTasks.filter((t) => t.id !== Number(id));
    localStorage.setItem('tasks', JSON.stringify(updatedTasks));

    navigate('/'); // 削除後にタスク一覧へリダイレクト
  };

  return (
    <div className="min-h-screen bg-gray-100 flex flex-col items-center p-6">
      <h2 className="text-2xl font-bold text-gray-800 mb-6">タスクの詳細</h2>

      <div className="w-full max-w-lg bg-white shadow-md rounded-lg p-6">
        {task ? (
          <>
            <TaskDetail task={task} />
            <button
              onClick={handleDeleteTask}
              className="mt-6 px-6 py-3 bg-red-500 text-white font-semibold rounded-lg shadow hover:bg-red-600 transition"
            >
              削除
            </button>
          </>
        ) : (
          <p className="text-gray-500">タスクが見つかりません</p>
        )}
      </div>

      <button
        onClick={() => navigate('/')}
        className="mt-6 px-6 py-3 bg-gray-500 text-white font-semibold rounded-lg shadow hover:bg-gray-600 transition"
      >
        戻る
      </button>
    </div>
  );
};

export default TaskDetailPage;
```
components/TaskDetailは以下の記述

```javascript
import React from 'react';

const TaskDetail = ({ task }) => {
  if (!task) return <p>Task not found</p>;

  return (
    <div>
      <h2>{task.title}</h2>
      <p>{task.description}</p>
    </div>
  );
};

export default TaskDetail;
```

# 大本
いかにgithubリンクを載せたので大本確認したい人はどうぞ

https://github.com/quesman01/portfolio16-react-todo2