Next.js×Railsでdelete画面を作る。

https://qiita.com/gabakugik/items/882d02d12c3a30beea29
の続きで最後の部分の削除を実装していきます。

```/backend/app/controllers/todos_controller.rb
class TodosController < ApplicationController
    
    def index
        # 日付が新しい順に10件まで取得する
        @todos = Todo.all.order(created_at: :desc).limit(10)
    
        render json: @todos
    
    end
    
    def show
    
        @todo = Todo.find(params[:id])

    render json: @todo
    end

    def create
          
        @todo = Todo.new(todo_params)
      
        if @todo.save
            render json: @todo, status: :created, location: @todo
          else
            render json: @todo.errors, status: :unprocessable_entity
          end
        end
      
        def update
          @todo = Todo.find(params[:id])
      
          if @todo.update(todo_params)
            render json: @todo
          else
            render json: @todo.errors, status: :unprocessable_entity
          end
        end
        
          # DELETE /todos/:id
          def destroy
            @todo = Todo.find(params[:id])
            @todo.destroy
          
          end
        
        def todo_params
          params.require(:todo).permit(:title, :content)
    end
end

```

```/frontend/components/DeleteTodoButton.tsx
import { useRouter } from 'next/navigation';
import useSWR, { mutate } from 'swr';
import axios from 'axios';

type DeleteTodoButtonProps = {
  id: number;
};

// Simple fetcher function if you need it for future use
const fetcher = (url: string) => axios.get(url).then(res => res.data);

// Todoを削除するボタン
const DeleteTodoButton = ({ id }: DeleteTodoButtonProps) => {
  const router = useRouter();

  // Todoを削除する関数
  const handleDelete = async () => {
    // 確認のダイアログを表示
    if (!confirm('本当に削除しますか？')) {
      return;
    }

    try {
      // APIを呼び出して、Todoを削除する
      await axios.delete(`http://localhost:3000/todos/${id}`);

      // 削除に成功したら、SWRのキャッシュを無効化して再取得
      mutate('/todos', async (todos: any) => {
        // ローカルで楽観的に削除する
        return todos ? todos.filter((todo: any) => todo.id !== id) : [];
      }, false);

      // トップページに遷移
      router.push('/');
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <button
      onClick={handleDelete}
      className="mt-3 ml-auto flex justify-center py-2 px-8 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
    >
      Delete
    </button>
  );
};

export default DeleteTodoButton;

```

```/frontend/app/todos/[id]/page.tsx

"use client";

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import useSWR from 'swr';
import Link from 'next/link';
import Todo from '@/components/Todo';
import { TodoType } from '@/types/Todo';
import axios from 'axios';
import DeleteTodoButton from '@/components/DeleteTodoButton';

// Fetcher function for SWR
const fetcher = (url: string) => axios.get(url).then(res => res.data);

// Todo詳細ページを表示するコンポーネント
const TodoDetail = ({ params }: { params: { id: string } }) => {
  // ルーティング情報を取得する
  const router = useRouter();
  const { id } = params;

  // SWRを使ってデータを取得する
  const { data: todo, error } = useSWR<TodoType>(id ? `http://localhost:3000/todos/${id}` : null, fetcher);

  // エラーが発生した場合の処理
  if (error) return <div>Failed to load</div>;

  // Todoを取得中の場合は「Loading...」を表示する
  if (!todo) return <div>Loading...</div>;

  return (
    <div className="flex justify-center items-center">
      <div className="flex flex-col space-y-6 w-3/4 max-w-lg pt-10">
        <label className="block text-xl font-bold text-gray-700">Todo</label>
        <Todo todo={todo} />
        <div className="flex justify-end">
          <Link
            href={`/todos/${id}/edit`}
            className="mt-auto font-medium text-blue-600 hover:bg-blue-300 focus:outline-none mr-12"
          >
            Edit
          </Link>
          <Link
            href="/"
            className="mt-auto font-medium text-blue-600 hover:bg-blue-300 focus:outline-none"
          >
            Back
          </Link>
        </div>
        {/* 削除ボタンコンポーネントを追加 */}
        <DeleteTodoButton id={todo.id} />
      </div>
    </div>
  );
};


export default TodoDetail;

```

これで終わりです。
frontendが難しかったですが、できました。
ぜひ皆さんもやってみてください。

frontendのフォルダ構成
![スクリーンショット 2024-08-27 193558.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270337/cc6fbd63-5d27-6853-876f-1e66766097a2.png)