回答編集履歴
6
あ
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
あ
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
w
test
CHANGED
@@ -96,9 +96,9 @@
|
|
96
96
|
結局、setFormには、{agreement:false} という新しいオブジェクトが渡されることになります。
|
97
97
|
|
98
98
|
この結果、useState に設定していた form という名前のオブジェクトの**状態変化**が React によって検知され、コンポーネントが再レンダリングされることになります。
|
99
|
-
再レンダリングの結果、 checked={form.
|
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
|
-
|
160
|
+
計算プロパティ名によって自動的にどのチェックボックスがチェックされたのかを判別しています。
|
160
161
|
|
3
追記
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
|
-
|
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
修正
test
CHANGED
@@ -1,16 +1,38 @@
|
|
1
1
|
|
2
|
-
まず、{..
|
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
|
-
|
32
|
+
`{[e.target.name]: e.target.checked}` は
|
33
|
+
`{agreement : false}` というオブジェクトとして評価されます。
|
16
34
|
|
35
|
+
なぜ[ ]でプロパティ名を囲むかというと、そうしないと識別子であるプロパティ名にピリオドが含まれていると解釈されて、構文エラーになるからです。
|
36
|
+
|
37
|
+
|
38
|
+
|
1
あ
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
|
|