Editがうまくいかない
解決したいこと
https://qiita.com/gabakugik/items/b0fcc09158d336e9e2a8
の続きです。
Editボタンを押すとLoadingになってしまう。
Nexts.jsとRuby on RailsでCRUDWebアプリをつくっています。
Editボタンを押すと飛ぶようになりましたが更新ができません。
解決方法を教えて下さい。
できました。ありがとうございます。
下記の通りにやったらできました。
該当するソースコード
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
def todo_params
params.require(:todo).permit(:title, :content)
end
end
"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';
// 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/` : 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>
</div>
</div>
);
};
export default TodoDetail;
"use client"
import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import axios from 'axios';
type EditTodoFormProps = {
id: number;
};
// Todo を編集するフォーム
const EditTodoForm = ({ id }: EditTodoFormProps) => {
const router = useRouter();
// フォームの入力値を管理するstate
const [title, setTitle] = useState('');
// フォームの入力値を管理するstate
const [content, setContent] = useState('');
// idが変更されたら(=Todo編集ページを開いたら)、Todoを取得してフォームの初期値を設定する
useEffect(() => {
// idが存在しない場合は、処理を中断する
const fetchTodo = async () => {
try {
// idを元にTodoを取得する
const res = await axios.get(`http://localhost:3000/todos/${id}`);
// フォームの初期値を設定する
const { title, content } = res.data;
setTitle(title);
setContent(content);
} catch (err) {
console.log(err);
}
};
// idが存在する場合は、Todoを取得する
if (id) {
fetchTodo();
}
}, [id]);
// フォームの入力値を更新する関数
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
// APIを呼び出して、Todoを更新する
await axios.put(`http://localhost:3000/todos/${id}`, { todo: { title, content } });
// Todoの更新に成功したら、Todo詳細ページに遷移する
router.push(`/todos/${id}`);
} catch (error) {
console.error(error);
}
};
return (
<div className="space-y-6 py-16">
<form
onSubmit={handleSubmit}
className="space-y-6"
>
<label className="block text-xl font-bold text-gray-700">Edit Todo</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="タイトル"
className="block w-full py-2 pl-3 pr-4 text-base border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="本文"
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
/>
<button
type="submit"
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"
>
Update
</button>
</form>
</div>
);
};
export default EditTodoForm;
"use client";
import { useParams } from 'next/navigation';
import Link from 'next/link';
import EditTodoForm from '@/components/EditTodoForm';
const EditTodoPage = () => {
// Use useParams to retrieve the id from the URL
const { id } = useParams<{ id: string }>();
// Display loading state until id is available
if (!id) {
return <div>Loading...</div>;
}
return (
<div className="flex justify-center items-center">
<div className="flex flex-col w-3/4 max-w-lg">
<EditTodoForm id={parseInt(id)} />
<Link
href="/"
className="ml-auto font-medium text-blue-600 hover:bg-blue-300 focus:outline-none"
>
Back
</Link>
</div>
</div>
);
};
export default EditTodoPage;
自分で試したこと
環境がだめになったしまったので、一からもう一度作り直した。
appがひとつ少なくなった。
ここ参考になるよとかここのコードみてごらんとかヒントだけでもいいのでよろしくお願いします。