質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

1回答

1094閲覧

Reactでボタンを2回押さないと処理が実行されないので、1回押すだけで処理を実行できるようにしたい

orange-purines

総合スコア0

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2024/01/24 08:04

実現したいこと

-完了ボタンを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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2024/01/25 07:27

Buttonはどのようなコンポーネントですか?
guest

回答1

0

完了ボタンを押したときに 「saveTask の実行 → handleClear() の実行」という処理の流れになっていますが、このような実装方法だと、

idが id_001 のタスクの完了ボタンを押したあと、次に id_002 のタスクの完了ボタンを押したときの挙動は、このようになります。

saveTask の中で setSelectedTask("id_002") が実行される。
その次、handleClear に進むが、その中で selectedTask の値は "id_001" のまま。

原因はこちらの記事をご参照ください。https://qiita.com/honey32/items/ee8d1577e68b0d58678d

今回については、 selectedTask というステートに、一時変数でよいものをわざわざワンバウンドさせる 必要がありません。

tsx

1saveTask(task.id); 2handleClear();

ではなく

tsx

1handleClear(task.id)

として、handleClear の中では、受け取った taskId を使って処理を進めればバグが治ると思います。

投稿2024/02/01 15:57

honey32

総合スコア246

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問