実現したいこと
-完了ボタンを2回押さないと処理が実行されないので、1回押すだけで処理が実行できるようにしたい
前提
React✖️TypeScriptでTodoListを実装しています。
フォームに文字を入力し追加を押すとTodoListが生成されます。
生成されたTodoListには、完了ボタンと削除ボタンがあり、
「完了ボタンを押したら完了したタスクというモーダルにタスクが移動し、削除ボタンを押したときは、モーダルで本当に削除するか確認し、「はい」なら削除、「いいえ」ならそのままTodoListに残す」
というものです。
現在、削除ボタンを押した際の処理は正常に動作しているのですが、完了ボタンは2回押さないと処理が実行されない状況です。
非同期処理やらuseEffect()など試したのですが、完了ボタンの動作が正常になると削除ボタンを押したときも完了したタスクに移動してしまう。。。など手詰まりになってしまったので、ご教授お願いします。
発生している問題・エラーメッセージ
完了ボタンを2回押さないと処理が実行されない
該当のソースコード
TypeScript
1ソースコード 2//追加されたタスクを表示するコンポーネント 3import React, { useState, memo } from "react"; 4import { Delete } from "./todoDelete"; 5import { Button } from "../ui/button"; 6 7// ListItem の型定義 8type ListItem = { 9 id: string; 10 text: string; 11 date?: Date; 12}; 13// Props の型定義 14type ListProps = { 15 list: ListItem[]; 16 setList: React.Dispatch<React.SetStateAction<ListItem[]>>; 17 //タスク完了時のコールバック関数 18 handleTaskComplete: (completedTask: ListItem, date: Date) => void; 19}; 20 21export const List = memo((props: ListProps) => { 22 //削除ボタンの状態 23 const [showDelete, setShowDelete] = useState<boolean>(false); 24 //選択されているタスクのIDを保持する 25 const [selectedTask, setSelectedTask] = useState<string | null>(null); 26 //完了したタスクを管理するState 27 const [completedTasks, setCompletedTasks] = useState<ListItem[]>([]); 28 29 //削除ボタンの初期値 30 const openDelete = () => { 31 setShowDelete(true); 32 }; 33 //ボタン押下時の対応するIDの保存 34 const saveTask = (id: string | null) => { 35 setSelectedTask(id); 36 }; 37 //削除するタスクを元のリストから削除 38 const handleDelete = () => { 39 props.setList(props.list.filter((task) => task.id !== selectedTask)); 40 }; 41 42 //完了ボタンが押された時の処理 43 const handleClear = () => { 44 console.log("handleClear called"); 45 //対象のタスクの選定 46 const completedTask = props.list.find((task) => task.id === selectedTask); 47 if (completedTask) { 48 // 完了したタスクを元のリストから削除 49 props.setList((prevList) => prevList.filter((task) => task.id !== selectedTask)); 50 //現在の日時を取得 51 const date = new Date(); 52 //完了したタスクに完了日時を追加 53 completedTask.date = date; 54 //handleTaskCompleteにタスクを渡して通知 55 console.log("props.list:", props.list); 56 props.handleTaskComplete(completedTask, date); 57 // 完了したタスクを完了リストに追加 58 console.log("Adding completedTask to completedTasks"); 59 setCompletedTasks((prevCompletedTasks) => { 60 return [...prevCompletedTasks, completedTask]; 61 }); 62 }; 63 }; 64 65 66 return ( 67 <> 68 <div className="mt-6 flex flex-col items-center list-none"> 69 {props.list.map((task) => ( 70 <div className="table w-4/12 h-12"> 71 <li className="bg-[#ffffff] border-solid border border-[#9a49f2] p-4 table-cell align-middle rounded" 72 key={task.id}> 73 <div className="flex items-center"> 74 <p className="mr-auto text-[#9a49f2]/75 font-bold">{task.text}</p> 75 <div> 76 <Button variant="outline" size="sm" 77 onClick={() => { 78 saveTask(task.id); 79 handleClear(); 80 }} 81 className="text-[#f0eef7] bg-pink-600 font-bold rounded-full">完了</Button> 82 <Button variant="outline" size="sm" 83 onClick={() => { 84 // 先に記述した方が処理される 85 openDelete(); 86 saveTask(task.id); 87 }} 88 className="text-[#f0eef7] bg-indigo-600 font-bold rounded-full">削除</Button> 89 </div> 90 </div> 91 </li> 92 </div> 93 ))} 94 {/* 削除タスクの受け渡し */} 95 <Delete showDelete={showDelete} setShowDelete={setShowDelete} handleDelete={handleDelete} /> 96 </div> 97 </> 98 ); 99}); 100 101export default List;
試したこと
aysnc,awaitでの非同期処理
useEffect()での制御
補足情報(FW/ツールのバージョンなど)
vscode
docker
