回答編集履歴

6

2023/11/29 15:03

投稿

退会済みユーザー
test CHANGED
@@ -159,4 +159,4 @@
159
159
  handleFormCheck 関数の中身は質問から変えていません。
160
160
  計算プロパティ名によって自動的にどのチェックボックスがチェックされたのかを判別しています。
161
161
 
162
- (公式の[この例](https://ja.react.dev/learn/updating-objects-in-state#copying-objects-with-the-spread-syntax)の方がもっと有用性がわかりやすいと思います)
162
+ スプレッド構文を使うことの有用性に着目するならば、公式の[この例](https://ja.react.dev/learn/updating-objects-in-state#copying-objects-with-the-spread-syntax)の方がもっとわかりやすいと思います)

5

2023/11/29 14:56

投稿

退会済みユーザー
test CHANGED
@@ -159,3 +159,4 @@
159
159
  handleFormCheck 関数の中身は質問から変えていません。
160
160
  計算プロパティ名によって自動的にどのチェックボックスがチェックされたのかを判別しています。
161
161
 
162
+ (公式の[この例](https://ja.react.dev/learn/updating-objects-in-state#copying-objects-with-the-spread-syntax)の方がもっと有用性がわかりやすいと思います)

4

2023/11/29 13:21

投稿

退会済みユーザー
test CHANGED
@@ -96,9 +96,9 @@
96
96
  結局、setFormには、{agreement:false} という新しいオブジェクトが渡されることになります。
97
97
 
98
98
  この結果、useState に設定していた form という名前のオブジェクトの**状態変化**が React によって検知され、コンポーネントが再レンダリングされることになります。
99
- 再レンダリングの結果、 checked={form.concent}  となので、 checked=false 、つまりチェックが外れた状態で描画されます。
99
+ 再レンダリングの結果、 checked={form.agreement} なので、 checked=false 、つまりチェックが外れた状態で描画されます。
100
100
 
101
- スプレッド構文を使わず下記のようにすればよいと思われるかもしれません。
101
+ ここで、スプレッド構文を使わず下記のようにすればよいと思われるかもしれません。
102
102
  ```
103
103
  const handleFormCheck = e => {
104
104
  form.agreement = e.target.checked;
@@ -106,14 +106,14 @@
106
106
  };
107
107
  ```
108
108
 
109
- しかし、この場合、formオブジェクト変更検知されず、チェック状態は変わりません。
109
+ しかし、この場合、formオブジェクトを直接変更しているため変更が検知されず、再レンダリングされません。
110
110
  参照:https://ja.react.dev/learn/updating-objects-in-state
111
111
 
112
112
  ---
113
113
 
114
114
  「1つのチェックボックスを切り替えるだけなのになんでこんなめんどくさいことをやってるのだろう」と思われるかもしれません。
115
115
  たしかに元のコードでは、計算プロパティ名を使わずとも、送信時にチェックボックスの状態を調べれば十分な気もします。
116
- また、下記のコードだと計算プロパティ名の便利さがわかると思い
116
+ 下記のようなコードだと計算プロパティ名の便利さが少しだけわかるかもしれせん
117
117
 
118
118
  ```js
119
119
  import { useState } from 'react';
@@ -154,7 +154,8 @@
154
154
  }
155
155
  ```
156
156
 
157
- この例では、「同意」に加えて「納得」のチェックボックスを追加します。
157
+ この例では、「同意」に加えて「納得」のチェックボックスを追加しています。それぞれ、agreementとconcent という名前を指定しており
158
- それぞれのチェックボックスをクリックした結果が、そのチェック状況に応じて表示されます。
158
+ チェックボックスをクリックした結果が、そのチェック状況に応じて表示されます。
159
+ handleFormCheck 関数の中身は質問から変えていません。
159
- ここで handleFormCheck 関数の中身は変えていませんが、計算プロパティ名によって自動的にどのチェックボックスがチェックされたのかを判別しています。
160
+ 計算プロパティ名によって自動的にどのチェックボックスがチェックされたのかを判別しています。
160
161
 

3

追記

2023/11/29 12:51

投稿

退会済みユーザー
test CHANGED
@@ -1,6 +1,5 @@
1
1
 
2
- まず、`{...form}`は、オブジェクトリテラルでのスプレッド構文です。
3
- [参照](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%AA%E3%83%86%E3%83%A9%E3%83%AB%E3%81%A7%E3%81%AE%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E6%A7%8B%E6%96%87)
2
+ (1)まず、`{...form}`は、オブジェクトリテラルでのスプレッド構文です。([参照](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%AA%E3%83%86%E3%83%A9%E3%83%AB%E3%81%A7%E3%81%AE%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E6%A7%8B%E6%96%87))
4
3
 
5
4
  オブジェクトを表す`{}`の中で`...form` と書くことで、formオブジェクトのキー(プロパティ名)と値の組が展開されます。
6
5
 
@@ -14,18 +13,16 @@
14
13
  let obj1 = { foo: "bar", x: 42 };
15
14
  let obj2 = { ...obj1, y: 13 }; // obj1 のプロパティ名と値の組が展開される。
16
15
  console.log(obj2);
17
-
18
- > { foo: "bar", x: 42, y: 13 }
16
+ >>> { foo: "bar", x: 42, y: 13 }
19
17
 
20
18
  let obj3 = {x: 50};
21
- let obj4 = {...obj2, ...obj3};
19
+ let obj4 = {...obj2, ...obj3}; // スプレッド構文を並べて書ける。それぞれのプロパティ名と値の組が展開される。
22
20
  console.log(obj4);
21
+ >>> { foo: "bar", x: 50, y: 13 } // 展開した結果、x が重複するのでマージされ、値は50になる。
22
+ ```
23
+  
23
24
 
24
- > { foo: "bar", x: 50, y: 13 } // x が重複するので、マージさ、値は50になる。
25
- ```
26
-
27
- 次に、`[e.target.name]: e.target.checked` については、前半でプロパティ名を変数で表現しています。
28
- [参照:計算プロパティ名](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer#%E8%A8%88%E7%AE%97%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D)
25
+ (2)次に、`[e.target.name]: e.target.checked`部分すがれは前半でプロパティ名を式で表現しているものです。([参照:計算プロパティ名](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer#%E8%A8%88%E7%AE%97%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D))
29
26
 
30
27
  たとえば、`e.target.name`が「agreement」、
31
28
  `e.target.checked` が「false」ならば、
@@ -33,6 +30,131 @@
33
30
  `{agreement : false}` というオブジェクトとして評価されます。
34
31
 
35
32
  なぜ[ ]でプロパティ名を囲むかというと、そうしないと識別子であるプロパティ名にピリオドが含まれていると解釈されて、構文エラーになるからです。
33
+ (`{'e.target.name': e.target.checked}`と書けばエラーにはなりませんが、これだとプロパティ名が単なる「e.target.name」という文字列になってしまい、式として評価されません)
36
34
 
35
+  
36
+ (3)スプレッド構文を使うと、使われた元のオブジェクトのプロパティ名が、**新しいオブジェクト**にコピーされます。
37
37
 
38
+ ---
38
39
 
40
+ (1)~(3)を念頭に置いて元のコードを追ってみます。
41
+ ```js
42
+ const [form, setForm] = useState({
43
+ agreement:true
44
+ });
45
+ ```
46
+ ここで、form オブジェクトの初期値として、 {agreement: true}がセットされています。
47
+ 同時にformのステート変更用の関数の名前として、setFormが設定されます。
48
+  
49
+  
50
+
51
+ ```jsx
52
+ <input id='agreement' name='agreement' type='checkbox'
53
+ checked={form.agreement}
54
+ onChange={handleFormCheck} /><br />
55
+ ```
56
+ チェックボックスの動作・外観を定義している部分です。
57
+ `checked` つまりチェック状態を form オブジェクトの agreement プロパティに紐付け、チェックボックスをクリックした時のハンドラを handleFormCheck 関数に設定しています。
58
+
59
+  
60
+  
61
+ ```js
62
+ const handleFormCheck = e => {
63
+ setForm({
64
+ ...form,
65
+ [e.target.name]: e.target.checked
66
+ });
67
+ };
68
+ ```
69
+ チェックボックスをクリックするとこの部分が実行されます(前述 onChange={handleFormCheck} )。
70
+
71
+ チェックボックスのname属性が「agreement」となっているので、クリックしたときに `e.target.name` は「agreement」と評価されます。
72
+ また、 `e.target.checked` はクリックされた後のチェック状態(チェックが入ればtrue、外されればfalse)になります。
73
+
74
+ 仮に、チェックボックスにチェックが入っている状態でクリックしたと仮定しましょう。
75
+ このとき、このコードの部分は下記のように評価されます。
76
+ ```
77
+ setForm({
78
+ ...form,
79
+ agreement: false // チェックが外されたのでfalseになる。
80
+ })
81
+ ```
82
+
83
+ そして、form は もともとagreement というプロパティを持っているので、
84
+ ```
85
+ setForm({
86
+ agreement: true,
87
+ agreement: false
88
+ })
89
+ ```
90
+ となり、重複しているプロパティ名 agreement がマージされて、その値は false に上書きされます。
91
+ ```
92
+ setForm({
93
+ agreement: false
94
+ })
95
+ ```
96
+ 結局、setFormには、{agreement:false} という新しいオブジェクトが渡されることになります。
97
+
98
+ この結果、useState に設定していた form という名前のオブジェクトの**状態変化**が React によって検知され、コンポーネントが再レンダリングされることになります。
99
+ 再レンダリングの結果、 checked={form.concent}  となので、 checked=false 、つまりチェックが外れた状態で描画されます。
100
+
101
+ スプレッド構文を使わず下記のようにすればよいと思われるかもしれません。
102
+ ```
103
+ const handleFormCheck = e => {
104
+ form.agreement = e.target.checked;
105
+ setForm(form);
106
+ };
107
+ ```
108
+
109
+ しかし、この場合、formオブジェクトの変更は検知されず、チェック状態は変わりません。
110
+ 参照:https://ja.react.dev/learn/updating-objects-in-state
111
+
112
+ ---
113
+
114
+ 「1つのチェックボックスを切り替えるだけなのになんでこんなめんどくさいことをやってるのだろう」と思われるかもしれません。
115
+ たしかに元のコードでは、計算プロパティ名を使わずとも、送信時にチェックボックスの状態を調べれば十分な気もします。
116
+ また、下記のコードだと、計算プロパティ名の便利さがわかると思います。
117
+
118
+ ```js
119
+ import { useState } from 'react';
120
+
121
+ export default function FormTextarea() {
122
+ const [form, setForm] = useState({
123
+ agreement:true, concent:true
124
+ });
125
+
126
+ const handleFormCheck = e => {
127
+ setForm({
128
+ ...form,
129
+ [e.target.name]: e.target.checked
130
+ });
131
+ };
132
+
133
+ const show = () => {
134
+ console.log(`同意確認:${form.agreement ? '同意': '反対'}`);
135
+ };
136
+
137
+ return (
138
+ <form>
139
+ <label htmlFor='agreement'>同意項目:</label>
140
+ <input id='agreement' name='agreement' type='checkbox'
141
+ checked={form.agreement}
142
+ onChange={handleFormCheck} /><br />
143
+ <p> (同意しているか? {form.agreement ? '同意している': '反対している'})</p>
144
+
145
+ <label htmlFor=''>納得感:</label>
146
+
147
+ <input id='concent' name='concent' type='checkbox'
148
+ checked={form.concent}
149
+ onChange={handleFormCheck} /><br />
150
+ <p> (納得しているか? {form.concent ? '納得している': '不服である。'})</p>
151
+ <button type='button' onClick={show}>送信</button>
152
+ </form>
153
+ );
154
+ }
155
+ ```
156
+
157
+ この例では、「同意」に加えて「納得」のチェックボックスを追加します。
158
+ それぞれのチェックボックスをクリックした結果が、そのチェック状況に応じて表示されます。
159
+ ここで handleFormCheck 関数の中身は変えていませんが、計算プロパティ名によって自動的にどのチェックボックスがチェックされたのかを判別しています。
160
+

2

修正

2023/11/29 11:56

投稿

退会済みユーザー
test CHANGED
@@ -1,16 +1,38 @@
1
1
 
2
- まず、{.. form}は、オブジェクトリテラルでのスプレッド構文です。
2
+ まず、`{...form}`は、オブジェクトリテラルでのスプレッド構文です。
3
3
  [参照](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%AA%E3%83%86%E3%83%A9%E3%83%AB%E3%81%A7%E3%81%AE%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E6%A7%8B%E6%96%87)
4
4
 
5
- オブジェクトを表す{}の中で...form と書くことで、formオブジェクトのキーと値の組が展開されます。
5
+ オブジェクトを表す`{}`の中で`...form` と書くことで、formオブジェクトのキー(プロパティ名)と値の組が展開されます。
6
6
 
7
+ `{}`の中に、カンマで区切って、他のプロパティ名:値の組を書くことも可能です。
8
+ またスプレッド構文を書くことも可能です。
9
+
10
+ 展開した結果プロパティ名が重複する場合は、マージされ、値は上書きされます。
11
+
12
+ 例:
13
+ ```js
14
+ let obj1 = { foo: "bar", x: 42 };
15
+ let obj2 = { ...obj1, y: 13 }; // obj1 のプロパティ名と値の組が展開される。
16
+ console.log(obj2);
17
+
18
+ > { foo: "bar", x: 42, y: 13 }
19
+
20
+ let obj3 = {x: 50};
21
+ let obj4 = {...obj2, ...obj3};
22
+ console.log(obj4);
23
+
24
+ > { foo: "bar", x: 50, y: 13 } // x が重複するので、マージされ、値は50になる。
25
+ ```
26
+
7
- 次に、[e.target.name]: e.target.checked
27
+ 次に、`[e.target.name]: e.target.checked` については、前半でプロパティ名を変数で表現しています。
8
- については、前半でプロパティを変数で表現しています。
9
28
  [参照:計算プロパティ名](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer#%E8%A8%88%E7%AE%97%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D)
10
- たとえば、e.target.nameが「agreement」、
11
- e.target.checked が「false」ならば、
12
- {[e.target.name]: e.target.checked} は
13
- {agreement : false} というオブジェクトとして評価されます。
14
29
 
30
+ たとえば、`e.target.name`が「agreement」、
31
+ `e.target.checked` が「false」ならば、
15
- なぜ[ ]でプロパティを囲むかというと、そうしないと、「e.target.name」という一連の文字列として解釈されてしまう({'e.target.name' : false} となってしまう)からです。
32
+ `{[e.target.name]: e.target.checked}` は
33
+ `{agreement : false}` というオブジェクトとして評価されます。
16
34
 
35
+ なぜ[ ]でプロパティ名を囲むかというと、そうしないと識別子であるプロパティ名にピリオドが含まれていると解釈されて、構文エラーになるからです。
36
+
37
+
38
+

1

2023/11/29 10:41

投稿

退会済みユーザー
test CHANGED
@@ -12,6 +12,5 @@
12
12
  {[e.target.name]: e.target.checked} は
13
13
  {agreement : false} というオブジェクトとして評価されます。
14
14
 
15
- なぜ[ ]でプロパティを囲むかというと、そうしないと、「e.target.name」という一連の文字列として解釈されてしまうからです。
15
+ なぜ[ ]でプロパティを囲むかというと、そうしないと、「e.target.name」という一連の文字列として解釈されてしまう({'e.target.name' : false} となってしまう)からです。
16
- (つまり{'e.target.name' : false} となる)
17
16