回答編集履歴

2

追記

2022/01/22 14:55

投稿

hoshi-takanori
hoshi-takanori

スコア7895

test CHANGED
@@ -1,4 +1,4 @@
1
- コメント欄より
1
+ 質問への追記・修正依頼欄より
2
2
 
3
3
  > 実は今回質問させていただいたのはとある機能を実装するための一部分でして最終的には以下のような処理にしたいです。
4
4
  >
@@ -95,3 +95,61 @@
95
95
  - array1 は入力内容に基づいて計算できるので、毎回計算し直すと良いでしょう。
96
96
 
97
97
  という感じで、普通の JavaScript とはまったく違う考え方をする必要があります。
98
+
99
+ ---
100
+
101
+ コメント欄へのお返事
102
+
103
+ まず、`...` の意味はご存じでしょうか? これはスプレッド構文と言って、配列やオブジェクトの中身を取り出して、新しい配列やオブジェクトに埋め込む、という意味になります。
104
+ 参考: [JSのスプレッド構文を理解する - Qiita](https://qiita.com/akisx/items/682a4283c13fe336c547)
105
+
106
+ 例えば配列の場合、
107
+
108
+ ```js
109
+ const a = [1, 2, 3];
110
+ const b = [...a, 4];
111
+ ```
112
+
113
+ と書くと、`...a` の部分には a の中身が展開されて、b の値は `[1, 2, 3, 4]` になります。
114
+
115
+ > 配列の中身を書き換える場合、配列そのものと、値が変更されるオブジェクトは作り直す必要があります。
116
+
117
+ と書きましたが、例えば createInput を
118
+
119
+ ```js
120
+ const createInput = () => {
121
+ items.push({ amount: '', people: '' });
122
+ setItems(items)
123
+ };
124
+ ```
125
+
126
+ と書き換えると、追加ボタンを押しても何も起こらなくなります。これは、items の中身は書き変わったけど、items 自体は同じ配列なので、setItems しても値は変わってないとみなされてしまうためです。
127
+
128
+ 同様に、updateAmount で `const newItems = [...items];` としているのは、items 配列をコピーして setItems の時に新しい値として認識させるためです。
129
+
130
+ 次の `newItems[index] = { ...items[index], amount: value };` ですが、これはオブジェクトのスプレッド構文になります。例えば、
131
+
132
+ ```js
133
+ const x = { a: 1, b: 2, c: 3 };
134
+ const y = { ...x, a: 4 };
135
+ ```
136
+
137
+ とすると、`...x` の部分に x の中身が展開されるのは配列の場合と同様ですが、違うのは a というキーが重複していることですね。その場合、後ろに書いたものが優先されます。ので、y の値は `{ a: 1, b: 2, c: 3, a: 4 }` ではなく、後ろの `a: 4` が優先されて `{ a: 4, b: 2, c: 3 }` になります。
138
+
139
+ 今回の場合、items の各要素には amount と people しかないので、次のように書いても同じ結果になります。
140
+
141
+ ```js
142
+ newItems[index] = { amount: value, people: newItems[index].people };
143
+ ```
144
+
145
+ が、スプレッド構文を使うと amount だけを書き換えたい、ということが明確になりますし、amount と people 以外に情報が増えても大丈夫です。
146
+
147
+ それから、array1 を計算する部分ですが、
148
+
149
+ ```js
150
+ const amount = parseInt(item.amount) || 0;
151
+ const people = parseInt(item.people) || 0;
152
+ ```
153
+
154
+ 実は item.amount や item.people は文字列になってます。これは、<input> の value に渡す時には文字列にしておかないと空欄にできないためですが、文字列なので例えば abc とか入力されたら parseInt の結果は NaN という、エラーを表す特別な値になります。これを確実に数値にする (エラーだったら 0 にする) ために `|| 0` を付けています。
155
+ 参考: [JavaScript parseInt, paeseFloat が NaN になるとき 0 を返したい - かもメモ](https://chaika.hatenablog.com/entry/2020/11/04/083000)

1

誤字修正

2022/01/22 11:33

投稿

hoshi-takanori
hoshi-takanori

スコア7895

test CHANGED
@@ -44,7 +44,7 @@
44
44
  export const Game = () => {
45
45
  const [items, setItems] = useState([]);
46
46
 
47
- const createEntry = () => {
47
+ const createInput = () => {
48
48
  setItems([...items, { amount: '', people: '' }])
49
49
  };
50
50
 
@@ -71,7 +71,7 @@
71
71
 
72
72
  return (
73
73
  <div className="game">
74
- <button type="button" onClick={createEntry}>
74
+ <button type="button" onClick={createInput}>
75
75
  追加する
76
76
  </button>
77
77
  {items.map((item, i) => (
@@ -89,9 +89,9 @@
89
89
  ```
90
90
 
91
91
  ポイントは、
92
- - React では入力欄の数だけ state が必要です。入力欄の数が可変の場合は配列などを使いましょう。
92
+ - React では入力欄の数だけ状態 (state) が必要です。入力欄の数が可変の場合は配列などを使いましょう。
93
93
  - 1 行の内容 (金額と人数) を一つのオブジェクト { amount: 金額, people: 人数 } として、その配列を用意します。
94
94
  - 配列の中身を書き換える場合、配列そのものと、値が変更されるオブジェクトは作り直す必要があります。
95
95
  - array1 は入力内容に基づいて計算できるので、毎回計算し直すと良いでしょう。
96
96
 
97
- う感じで、普通の JavaScript とはまったく違う考え方をする必要があります。
97
+ う感じで、普通の JavaScript とはまったく違う考え方をする必要があります。