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

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

新規登録して質問してみよう
ただいま回答率
85.46%
React Native

React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

JavaScript

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

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

React.js

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

Q&A

解決済

1回答

943閲覧

Reactで一定回数クリックしたら数値が1に戻る定数を設定したい

nto300002

総合スコア1

React Native

React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

JavaScript

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

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

React.js

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

0グッド

0クリップ

投稿2021/09/19 07:18

前提・実現したいこと

reactにてtodoアプリを作成しています。
そこで、categoryの値を増やすhandleStateIncreaseという関数を設定し、クリックするごとに未着手→進行中→完了となるようにしたいのですが、完了状態になったあとにクリックすると下記のエラーメッセージが出てしまいます。
そこで、クリックしてcategoryの数値が3になった(完了と表示される)あとにクリックすると1(未着手)の状態に戻るというようにしたいのですが、調べてもなかなかうまく行かなかったのでなにかアドバイスがほしいです。
よろしくおねがいします。

発生している問題・エラーメッセージ

TypeError Cannot read property 'title' of undefined

該当のソースコード

React

1import React, { useState, useMemo } from "react"; 2 3export default function App() { 4 const initialState = { 5 tasks: [ 6 { 7 id: 1, 8 title: "title", 9 category: 1, 10 text: "" 11 } 12 ], 13 categories: [ 14 { 15 id: 1, 16 title: "未着手" 17 }, 18 { 19 id: 2, 20 title: "進行中" 21 }, 22 { 23 id: 3, 24 title: "完了" 25 } 26 ] 27 }; 28 const [tasks, setTasks] = useState(initialState.tasks); 29 const [categories, setCategories] = useState(initialState.categories); 30 const defaultItem = () => ({ id: 1, title: item, category: 1, text: "" }); 31 const [item, setItem] = useState(""); 32 33 const handleNewitem = (e) => setItem(e.target.value); 34 35 const handleSubmit = (e) => { 36 e.preventDefault(); 37 if (item === "") return; 38 setTasks((tasks) => [...tasks, defaultItem()]); 39 setItem(""); 40 }; 41 42 const handleRemoveItem = (index) => { 43 const newItems = [...tasks]; 44 newItems.splice(index, 1); 45 setTasks(newItems); 46 }; 47 48 //クリックしてcategoryの数値が3になった(完了と表示される)あとにクリックすると1(未着手)の状態に戻る 49 const handleStateIncrease = (index) => {   50 if (index > 3) return; 51 const newTasks = [...tasks]; 52 newTasks[index].category++; 53 setTasks(newTasks); 54 }; 55 56 const [filterQuery, setFilterQuery] = useState({}); 57 58 const filteredTask = useMemo(() => { 59 60 let tmpTasks = tasks; 61 62 tmpTasks = tmpTasks.filter((row) => { 63 if ( 64 filterQuery.category_id && 65 row.category !== parseInt(filterQuery.category_id) 66 ) { 67 return false; 68 } 69 return row; 70 }); 71 72 return tmpTasks; 73 }, [filterQuery, tasks]); 74 75 const handleFilter = (e) => { 76 const { name, value } = e.target; 77 setFilterQuery({ ...filterQuery, [name]: value }); 78 }; 79 80 return ( 81 <div className="wrap"> 82 <div className="input-group"> 83 <form onSubmit={handleSubmit}> 84 <input 85 value={item} 86 placeholder="Enterを押してください" 87 onChange={handleNewitem} 88 /> 89 [追加] 90 </form> 91 </div> 92 <div className="input-group"> 93 <div className="selectbox"></div> 94 </div> 95 96 <table> 97 <thead> 98 <tr> 99 <th>[タイトル]</th> 100 <th>[カテゴリー]</th> 101 </tr> 102 </thead> 103 104 <tbody> 105 {filteredTask.map((task, index) => { 106 return ( 107 <tr key={task.id}> 108 <td> 109 {task.title} 110 </td> 111 <td> 112 <span onClick={() => handleStateIncrease(index)}> 113 {task.category 114 ? categories.find((c) => c.id === task.category).title 115 : ""} 116 </span> 117 </td> 118 <td> 119 <button onClick={() => handleRemoveItem(index)}>削除</button> 120 </td> 121 </tr> 122 ); 123 })} 124 </tbody> 125 </table> 126 </div> 127 ); 128} 129

試したこと

if文を使った条件分岐をさせようとしましたが今度はクリックしても反応しませんでした。

補足情報(FW/ツールのバージョンなど)

OS Mac
node -v
v14.17.0

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

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

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

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

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

guest

回答1

0

ベストアンサー

集合X = {1, 2, 3} として、Xで定義される1to1かつontoな関数 f

  • f(1)= 2
  • f(2)= 3
  • f(3)= 1

を演算式で書くとすれば、f(x) = x % 3 + 1 と書けます。これを使えば、newTasksを作ってsetTasksするこの3行

javascript

1const newTasks = [...tasks]; 2newTasks[index].category++; 3setTasks(newTasks);

は、以下でいけるんちゃいます?

javascript

1setTasks(tasks.map((task, i) => ({ 2 ...task, 3 category: i !== index ? task.category : (task.category % 3 + 1) 4}))); 5

投稿2021/09/19 08:23

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

nto300002

2021/09/19 09:20

すごい!無事に解決できました!ありがとうございます!!!
退会済みユーザー

退会済みユーザー

2021/09/19 10:40

おおきにですぅ〜  大変おこがましいですけど、業務でのReact経験約4年半のワテからみて、nto300002さんの質問にあるコートの良い点が2つ: (1) onChangeやonClick に設定する各コールバックを入れておく変数名を、onXxxx ではなく handle をプレフィックスにして、handleXxxx にしている点 ※ただし、人によっては、「別にhandleXxxxじゃなくても onXxxxでいいでしょ?」派もいる。そういう人がテックリードだったりコードレビューする人だったりする場合もあるので、そこは適宜、うまいこと空気読んで合わせる。 (2) filteredTask をmapして作る各行の tr に、<tr key={task.id}> と、ちゃんとkey が書いてあって、かつ、map((task, index) の idex を使っての <tr key={index}> にしていない点 そして余計なお節介をひとつ: Reactというフレームワークの使い方とかお作法は、知識として調べて覚えることなので、やっていけばだんだんと身につきます。 なので、実務レベルで要件を満たすコンポーネントを書くときに試されるのは、今回でいえばsetTasksに渡す、新しいステイトを古いステイトから作るところをササッと、かつわかりやすいコードで書けるかどうかだったりします。(今後Reduxを使う機会があればちょっと込み入ったreducerを書くときなど)これはReactのお作法とは関係のない、JavaScript自体に関しての基礎力をベースにしたコーディング力ともいうべきものです。ひらたく言うと個人技の出やすい「腕の見せどころ」のひとつですわ。 気張ってや〜
nto300002

2021/09/19 13:52

変数名の命名とkeyの設定ですね!ありがとうございます。 とてもありがたいお褒めの言葉を頂き恐縮です。 ただ、上記のコードは大半がコピペなので、自分でもこれくらいのコードが書けるようにがんばります。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問