🖥️

Next.js入門8 Todoアプリ(タスク編集, 削除)

に公開

記事一覧

  1. Next.js × Docker 最速環境構築
  2. Next.js入門1 ページ追加
  3. Next.js入門2 コンポーネント
  4. Next.js入門3 無記名関数 & イベントハンドラー
  5. Next.js入門4 Hooks
  6. Next.js入門5 Todoアプリ(タスク一覧)
  7. Next.js入門6 Todoアプリ(タスク追加)
  8. Next.js入門7 Todoアプリ(タスク詳細)
  9. Next.js入門8 Todoアプリ(タスク編集, 削除)

タスク編集, 削除

ページを編集

詳細ページから編集, 削除をできるようにする
-> 編集はmap関数を使う
-> 削除はfilter関数を使う

  1. task/[index]/page.tsxを編集
"use client";

import { use, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/button";
import { Task } from "@/types/task";
// Modalコンポーネントをインポート
import { Modal } from "@/components/modal";

type Props = {
  params: Promise<{
    index: string;
  }>;
};

function Page({ params }: Props) {
  const index = parseInt(use(params).index);
  const router = useRouter();
  const [task, setTask] = useState<Task>();
  const [tasks, setTasks] = useState<Task[]>([]);
  // モーダルの状態を管理する
  const [isOpen, setIsOpen] = useState(false);

  useEffect(() => {
    const storedTasks = localStorage.getItem("tasks");

    if (storedTasks) {
      const parsedTasks = JSON.parse(storedTasks);
      setTasks(parsedTasks);
      setTask(parsedTasks[index]);
    }
  }, [index]);

  if (!task) {
    return;
  }

  return (
    <div className="flex flex-col gap-8 items-center p-16">
      <h1 className="text-4xl font-bold">タスク詳細</h1>

      <div className="w-full flex flex-col gap-8 border rounded-2xl p-8">
        <div className="flex gap-2 border-b">
          <label className="font-bold">タスク名</label>
          <p>{task.title}</p>
        </div>

        <div className="flex flex-col gap-2">
          <label className="font-bold border-b">内容</label>
          <p>{task.content}</p>
        </div>
      </div>

      <div className="w-full flex justify-between">
        <Button
          onClick={() => {
            router.push("/task");
          }}
        >
          戻る
        </Button>

        {/* 編集ボタンと削除ボタン */}
        <div className="flex gap-2">
          <Button onClick={() => setIsOpen(true)}>編集</Button>
          {/* 【重要】削除処理 */}
          <Button
            onClick={() => {
              // filterでindex番目以外のタスクを取得
              const newTasks = tasks.filter((_, i) => i !== index);
              // localStorageを更新
              localStorage.setItem("tasks", JSON.stringify(newTasks));

              // タスク一覧ページに遷移
              router.push("/task");
            }}
          >
            削除
          </Button>
        </div>
      </div>

      {/* isOpenがtrueの場合のみModalを表示 */}
      {isOpen && (
        // ModalコンポーネントのonCloseにモーダルを閉じる処理を渡す
        <Modal onClose={() => setIsOpen(false)}>
          <form className="flex flex-col gap-4 text-black border-black">
            {/* タスク名入力欄 */}
            <div className="flex flex-col gap-2">
              <label>タスク名</label>
              <input
                className="border p-2 rounded-xl"
                value={task.title}
                onChange={(e) => setTask({ ...task, title: e.target.value })}
              />
            </div>

            {/* タスク内容入力欄 */}
            <div className="flex flex-col gap-2">
              <label>内容</label>
              <textarea
                className="border p-2 rounded-xl"
                value={task.content}
                onChange={(e) => setTask({ ...task, content: e.target.value })}
              />
            </div>

            {/* キャンセルボタンと更新ボタン */}
            <div className="flex justify-end gap-4">
              <Button onClick={() => setIsOpen(false)}>キャンセル</Button>
              <Button
                // 【重要】更新処理
                onClick={() => {
                  // mapでindex番目のタスクのみ更新
                  const newTasks = tasks.map((t, i) =>
                    i === index ? task : t
                  );
                  // localStorageを更新
                  localStorage.setItem("tasks", JSON.stringify(newTasks));

                  // タスク一覧ページに遷移
                  router.push("/task");
                }}
              >
                更新
              </Button>
            </div>
          </form>
        </Modal>
      )}
    </div>
  );
}

export default Page;

http://localhost:3000/taskから詳細ページにアクセスし、編集と削除ができればOK

Discussion