Slide 1

Slide 1 text

How to make front-end Masanobu Naruse

Slide 2

Slide 2 text

2

Slide 3

Slide 3 text

3

Slide 4

Slide 4 text

シンプルさを支える基本の考えは ベクトル 4

Slide 5

Slide 5 text

Agenda 1. GUIアーキテクチャパターン 2. データ同期 3. エラーハンドリング 4. コンポーネント構造 5. まとめ 5

Slide 6

Slide 6 text

Agenda 1. GUIアーキテクチャパターン 2. データ同期 3. エラーハンドリング 4. コンポーネント構造 5. まとめ 6

Slide 7

Slide 7 text

MVC MVP MVVM 7

Slide 8

Slide 8 text

MVC 8

Slide 9

Slide 9 text

Complex 9

Slide 10

Slide 10 text

10

Slide 11

Slide 11 text

Simple 11

Slide 12

Slide 12 text

12

Slide 13

Slide 13 text

13

Slide 14

Slide 14 text

In software 14

Slide 15

Slide 15 text

Classic MVC 15

Slide 16

Slide 16 text

Model View Controller Classic MVC 16

Slide 17

Slide 17 text

Model View Controller Classic MVC 17

Slide 18

Slide 18 text

Model View Controller Classic MVC 18

Slide 19

Slide 19 text

Model View Controller Classic MVC 19

Slide 20

Slide 20 text

Model View Controller Classic MVC 20

Slide 21

Slide 21 text

Model View Controller Classic MVC 21

Slide 22

Slide 22 text

Model View Controller Classic MVC GUI Pattern 22

Slide 23

Slide 23 text

Model View Controller Classic MVC 23

Slide 24

Slide 24 text

Model View Controller Classic MVC Observer 24

Slide 25

Slide 25 text

Model View Controller Classic MVC Observer 25

Slide 26

Slide 26 text

Model View Controller Classic MVC Observer 26

Slide 27

Slide 27 text

MVC Framework ? 27

Slide 28

Slide 28 text

Model View Controller MVC2 28

Slide 29

Slide 29 text

MVP 29

Slide 30

Slide 30 text

MVP Humble View Supervising Controller 30

Slide 31

Slide 31 text

MVP Humble View Supervising Controller 31

Slide 32

Slide 32 text

Model View MVP (Humble View) Presenter 32

Slide 33

Slide 33 text

Model View MVP (Humble View) Presenter 33

Slide 34

Slide 34 text

Model View MVP (Humble View) Presenter 34

Slide 35

Slide 35 text

Model View MVP (Humble View) Presenter 35

Slide 36

Slide 36 text

Model View MVP (Humble View) Presenter 36

Slide 37

Slide 37 text

Model View MVP (Humble View) Presenter 37

Slide 38

Slide 38 text

Model View MVP (Humble View) Presenter 38

Slide 39

Slide 39 text

MVP Humble View Supervising Controller 39

Slide 40

Slide 40 text

Model View MVP (Super Vising Controller) Presenter 40

Slide 41

Slide 41 text

Model View MVP (Super Vising Controller) Presenter 41

Slide 42

Slide 42 text

Model View MVP (Super Vising Controller) Presenter 42

Slide 43

Slide 43 text

Model View MVP (Super Vising Controller) Presenter 43

Slide 44

Slide 44 text

Model View MVP (Super Vising Controller) Presenter 44

Slide 45

Slide 45 text

Model View MVP (Super Vising Controller) Presenter 45

Slide 46

Slide 46 text

Presenter Model View MVP (Super Vising Controller) 46

Slide 47

Slide 47 text

Model View MVP (Super Vising Controller) Observer Presenter 47

Slide 48

Slide 48 text

Model View MVP (Super Vising Controller) Presenter Observer 48

Slide 49

Slide 49 text

49

Slide 50

Slide 50 text

MVC は MVP になった 50

Slide 51

Slide 51 text

MVVM 51

Slide 52

Slide 52 text

Model View MVVM ViewModel 52

Slide 53

Slide 53 text

Model View MVVM ViewModel 53

Slide 54

Slide 54 text

Model View MVVM Binding ViewModel 54

Slide 55

Slide 55 text

Model View MVVM Binding ViewModel 55

Slide 56

Slide 56 text

Model View MVVM Binding ViewModel 56

Slide 57

Slide 57 text

Model View MVVM Binding ViewModel 57

Slide 58

Slide 58 text

MVC MVP MVVM 58

Slide 59

Slide 59 text

MVC MVP MVVM 59

Slide 60

Slide 60 text

重要なのは Model と View を分けること 糊付け方法が C, P, VM MVC MVP MVVM 60

Slide 61

Slide 61 text

というわけで 独自アーキテクチャ 61

Slide 62

Slide 62 text

MVX 62

Slide 63

Slide 63 text

MVX Model View Xxx 63

Slide 64

Slide 64 text

MVX Model View Xxx を提唱してたら 64

Slide 65

Slide 65 text

MVW 65

Slide 66

Slide 66 text

MVW Model View Whatever 66

Slide 67

Slide 67 text

Flux ? 67

Slide 68

Slide 68 text

68

Slide 69

Slide 69 text

69

Slide 70

Slide 70 text

Classic MVC は MVP となり その実装案のひとつとして Flux 70

Slide 71

Slide 71 text

重要なのは データフロー 71

Slide 72

Slide 72 text

重要なのは データフロー 72

Slide 73

Slide 73 text

Agenda 1. GUIアーキテクチャパターン 2. データ同期 3. エラーハンドリング 4. コンポーネント構造 5. まとめ 73

Slide 74

Slide 74 text

74

Slide 75

Slide 75 text

Id: 1 Name: naruse Twitter: @nrslib 75

Slide 76

Slide 76 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 76

Slide 77

Slide 77 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 77

Slide 78

Slide 78 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal 78

Slide 79

Slide 79 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal Name: nrs 79

Slide 80

Slide 80 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Modal Name: nrs 80

Slide 81

Slide 81 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 81

Slide 82

Slide 82 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Update Name: nrs 82

Slide 83

Slide 83 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 83

Slide 84

Slide 84 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 84

Slide 85

Slide 85 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib どこが悪いか もう一度 85

Slide 86

Slide 86 text

86

Slide 87

Slide 87 text

Id: 1 Name: naruse Twitter: @nrslib 87

Slide 88

Slide 88 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 88

Slide 89

Slide 89 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 89

Slide 90

Slide 90 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 90

Slide 91

Slide 91 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal 91

Slide 92

Slide 92 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal Name: nrs 92

Slide 93

Slide 93 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Modal Name: nrs 93

Slide 94

Slide 94 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 94

Slide 95

Slide 95 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 95

Slide 96

Slide 96 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 一時的な データ不整合 96

Slide 97

Slide 97 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 一時的な データ不整合 たとえるなら 97

Slide 98

Slide 98 text

98

Slide 99

Slide 99 text

どうすればよいか 99

Slide 100

Slide 100 text

100

Slide 101

Slide 101 text

Id: 1 Name: naruse Twitter: @nrslib 101

Slide 102

Slide 102 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 102

Slide 103

Slide 103 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 103

Slide 104

Slide 104 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal 104

Slide 105

Slide 105 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal Name: nrs 105

Slide 106

Slide 106 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal Name: nrs Update Name: nrs 106

Slide 107

Slide 107 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal Name: nrs 107

Slide 108

Slide 108 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib Modal Name: nrs Id: 1 Name: nrs Twitter: @nrslib 108

Slide 109

Slide 109 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Modal Name: nrs 109

Slide 110

Slide 110 text

Modal 110

Slide 111

Slide 111 text

Model View Controller Classic MVC 111

Slide 112

Slide 112 text

112

Slide 113

Slide 113 text

フォーム? 113

Slide 114

Slide 114 text

114

Slide 115

Slide 115 text

Id: 1 Name: naruse Twitter: @nrslib 115

Slide 116

Slide 116 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 116

Slide 117

Slide 117 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 117

Slide 118

Slide 118 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrslib 118

Slide 119

Slide 119 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 119

Slide 120

Slide 120 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Update Name: nrs 120

Slide 121

Slide 121 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 121

Slide 122

Slide 122 text

Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib あくまでサーバのデータで フロントを更新する 122

Slide 123

Slide 123 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Update Name: nrs 123

Slide 124

Slide 124 text

Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib Update Name: nrs 124

Slide 125

Slide 125 text

Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrslib Update Name: nrs Id: 1 Name: naruse Twitter: @nrs 125

Slide 126

Slide 126 text

Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs 126

Slide 127

Slide 127 text

Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs 127

Slide 128

Slide 128 text

Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs 信頼たるデータを 信頼しよう 128

Slide 129

Slide 129 text

Agenda 1. GUIアーキテクチャパターン 2. データ同期 3. エラーハンドリング 4. コンポーネント構造 5. まとめ 129

Slide 130

Slide 130 text

エラー 130

Slide 131

Slide 131 text

好きですか? エラー 131

Slide 132

Slide 132 text

エラーハンドリング 132

Slide 133

Slide 133 text

好きですか? エラーハンドリング 133

Slide 134

Slide 134 text

エラーハンドリングは ソフトウェアの使い勝手を 決定づける重要な要素 134

Slide 135

Slide 135 text

その上でもう一度 135

Slide 136

Slide 136 text

好きですか? エラーハンドリング 136

Slide 137

Slide 137 text

僕はあんまり好きじゃないです 137

Slide 138

Slide 138 text

本質的じゃないから 138

Slide 139

Slide 139 text

どうすれば? 139

Slide 140

Slide 140 text

エラーを整理してみよう 140

Slide 141

Slide 141 text

ユーザが回復できるエラー システムエラー 141

Slide 142

Slide 142 text

ユーザが回復できるエラー システムエラー 拾うべきは? 142

Slide 143

Slide 143 text

ユーザが回復できるエラー システムエラー 143

Slide 144

Slide 144 text

更にエラーを分ける 144

Slide 145

Slide 145 text

クライアントエラー サーバーエラー 145

Slide 146

Slide 146 text

クライアントの システムエラー クライアントの 回復可能エラー サーバーの システムエラー サーバーの 回復可能エラー サ ー バ ク ラ イ ア ン ト システムエラー 回復可能エラー 146

Slide 147

Slide 147 text

クライアントの システムエラー クライアントの 回復可能エラー サーバーの システムエラー サーバーの 回復可能エラー サ ー バ ク ラ イ ア ン ト システムエラー 回復可能エラー 147

Slide 148

Slide 148 text

クライアントの システムエラー クライアントの 回復可能エラー サーバーの システムエラー サーバーの 回復可能エラー サ ー バ ク ラ イ ア ン ト システムエラー 回復可能エラー 148

Slide 149

Slide 149 text

nrs@@example.com メールアドレス 149

Slide 150

Slide 150 text

nrs@@example.com メールアドレス メールアドレスの形式 ではありません 150

Slide 151

Slide 151 text

******** パスワード ******** パスワードの確認 151

Slide 152

Slide 152 text

******** パスワード ******** パスワードの確認 パスワードが 一致しません 152

Slide 153

Slide 153 text

153

Slide 154

Slide 154 text

画面ごとに異なるハンドリングのため それぞれの画面でハンドリング 154

Slide 155

Slide 155 text

画面ごとに異なるハンドリングのため それぞれの画面でハンドリング ディレクティブなどで共通化 155

Slide 156

Slide 156 text

クライアントの システムエラー クライアントの 回復可能エラー サーバーの システムエラー サーバーの 回復可能エラー サ ー バ ク ラ イ ア ン ト システムエラー 回復可能エラー 156

Slide 157

Slide 157 text

naruse ユーザ名 [email protected] メールアドレス ******** パスワード ******** パスワードの確認 157

Slide 158

Slide 158 text

naruse ユーザ名 [email protected] メールアドレス ******** パスワード ******** パスワードの確認 すでに登録されています すでに登録されています 158

Slide 159

Slide 159 text

159

Slide 160

Slide 160 text

Mail: [email protected] Name: naruse Password: ******** 160

Slide 161

Slide 161 text

Mail: [email protected] Name: naruse Password: ******** duplicated-email, duplicated-username 161

Slide 162

Slide 162 text

Mail: [email protected] Name: naruse Password: ******** duplicated-email, duplicated-username duplicated-email だからメール欄に エラー表示して 162

Slide 163

Slide 163 text

Mail: [email protected] Name: naruse Password: ******** duplicated-email, duplicated-username duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して 163

Slide 164

Slide 164 text

duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して 164

Slide 165

Slide 165 text

duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して 画面ごとに ハンドリング? 165

Slide 166

Slide 166 text

166

Slide 167

Slide 167 text

167

Slide 168

Slide 168 text

登録済みのメールアドレスです このユーザ名はすでに取得されています naruse ユーザ名 [email protected] メールアドレス ******** パスワード ******** パスワードの確認 168

Slide 169

Slide 169 text

登録済みのメールアドレスです このユーザ名はすでに取得されています naruse ユーザ名 [email protected] メールアドレス ******** パスワード ******** パスワードの確認 これなら? 169

Slide 170

Slide 170 text

170

Slide 171

Slide 171 text

duplicated-email だからメール欄に エラー表示して 171

Slide 172

Slide 172 text

duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して 172

Slide 173

Slide 173 text

そのほかにも duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して 173

Slide 174

Slide 174 text

そのほかにも duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して アレやコレや 174

Slide 175

Slide 175 text

エラーコードに従って エラーメッセージを表示 そのほかにも duplicated-email だからメール欄に エラー表示して duplicated-username だからユーザ名欄に エラー表示して アレやコレや 175

Slide 176

Slide 176 text

どう実現する? 176

Slide 177

Slide 177 text

通信ライブラリを ラップする 177

Slide 178

Slide 178 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 178

Slide 179

Slide 179 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 179

Slide 180

Slide 180 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 180

Slide 181

Slide 181 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 181

Slide 182

Slide 182 text

const notifyErrorToMessageService: IErrorNotifier = (response: IResponse) => { response.errors .map(x => x.message) .forEach(message => messageService.addMessage(MessageType.Error, message) ); }; 182

Slide 183

Slide 183 text

const notifyErrorToMessageService: IErrorNotifier = (response: IResponse) => { response.errors .map(x => x.message) .forEach(message => messageService.addMessage(MessageType.Error, message) ); }; 183

Slide 184

Slide 184 text

{{head}}
{{tailMessage}}
... @Component export default class NotifyMessage extends Vue { ... public get hasAnyMessage(): boolean { return this.messageService.hasAnyMessage; } public get head(): string { return this.messageService.headMessage; } public get tail(): string[] { return this.messageService.tailMessages; } } 184

Slide 185

Slide 185 text

{{head}}
{{tailMessage}}
... @Component export default class NotifyMessage extends Vue { ... public get hasAnyMessage(): boolean { return this.messageService.hasAnyMessage; } public get head(): string { return this.messageService.headMessage; } public get tail(): string[] { return this.messageService.tailMessages; } } 185

Slide 186

Slide 186 text

細かく制御したい ときもある 186

Slide 187

Slide 187 text

入力画面の難易度が高い エラー発生個所がわかりづらい たとえば 187

Slide 188

Slide 188 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 188

Slide 189

Slide 189 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 189

Slide 190

Slide 190 text

export default class Apios { public static post(url: string, data?: any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ): Promise> { const onError = this._selectErrorNote(params.onError); ... return new Promise>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler(resolve, reject, e, onError); }); }); 呼び出し側がエラーハンドラを 設定できるように受け口を用意 190

Slide 191

Slide 191 text

Callback を渡すようになるので 必然的に Promise を使わなくなる 191

Slide 192

Slide 192 text

Callback を渡すようになるので 必然的に Promise を使わなくなる 192

Slide 193

Slide 193 text

Promise 地獄 193

Slide 194

Slide 194 text

Promise を使えるようにするより 場合分けをしっかりしたほうがいい 194

Slide 195

Slide 195 text

できごと ハンドリング 成功 失敗 例外 セッション切れ 権限変更 (パーミッション変更) 195

Slide 196

Slide 196 text

できごと ハンドリング 成功 Callback 失敗 例外 セッション切れ 権限変更 (パーミッション変更) 196

Slide 197

Slide 197 text

できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 セッション切れ 権限変更 (パーミッション変更) 197

Slide 198

Slide 198 text

できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ 権限変更 (パーミッション変更) 198

Slide 199

Slide 199 text

できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) 199

Slide 200

Slide 200 text

できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 200

Slide 201

Slide 201 text

できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 201

Slide 202

Slide 202 text

public static post(url: string, data?: any, onSuccess: T => void, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ) できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 202

Slide 203

Slide 203 text

public static post(url: string, data?: any, onSuccess: T => void, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler; config?: AxiosRequestConfig; } ) できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 203

Slide 204

Slide 204 text

基本は何もしなくてよくて 必要なときに差し込める というのが大事 204

Slide 205

Slide 205 text

Agenda 1. GUIアーキテクチャパターン 2. データ同期 3. エラーハンドリング 4. コンポーネント構造 5. まとめ 205

Slide 206

Slide 206 text

コンポーネント構造のテーマ 1. コンポーネント構造 2. ページ遷移や通信を行う箇所 3. Flux 系のライブラリの使いどころ 4. データの保持は誰の役目? 206

Slide 207

Slide 207 text

コンポーネント構造のテーマ 1. コンポーネント構造 2. ページ遷移や通信を行う箇所 3. Flux 系のライブラリの使いどころ 4. データの保持は誰の役目? 207

Slide 208

Slide 208 text

まずはいわゆる オブジェクト指向プログラミング 208

Slide 209

Slide 209 text

シンプルな オブジェクト同士の構造は? 209

Slide 210

Slide 210 text

ObjectA ObjectB 210

Slide 211

Slide 211 text

ObjectA ObjectB 211

Slide 212

Slide 212 text

ObjectA ObjectB Method Call 212

Slide 213

Slide 213 text

ObjectA ObjectB Method Call Method Call 213

Slide 214

Slide 214 text

ObjectA ObjectB Method Call Method Call 214

Slide 215

Slide 215 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 215

Slide 216

Slide 216 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 216

Slide 217

Slide 217 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 217

Slide 218

Slide 218 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 相互参照 218

Slide 219

Slide 219 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 相互参照 コンストラクタに this を渡してると 大抵ヤバイ 219

Slide 220

Slide 220 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 220

Slide 221

Slide 221 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 221

Slide 222

Slide 222 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 222

Slide 223

Slide 223 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 223

Slide 224

Slide 224 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 224

Slide 225

Slide 225 text

ObjectA ObjectB 225

Slide 226

Slide 226 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 226

Slide 227

Slide 227 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 227

Slide 228

Slide 228 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 228

Slide 229

Slide 229 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 229

Slide 230

Slide 230 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 230

Slide 231

Slide 231 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 231

Slide 232

Slide 232 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 232

Slide 233

Slide 233 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 233

Slide 234

Slide 234 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 234

Slide 235

Slide 235 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 235

Slide 236

Slide 236 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 236

Slide 237

Slide 237 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 237

Slide 238

Slide 238 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 238

Slide 239

Slide 239 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 239

Slide 240

Slide 240 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 240

Slide 241

Slide 241 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 241

Slide 242

Slide 242 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 242

Slide 243

Slide 243 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 243

Slide 244

Slide 244 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 244

Slide 245

Slide 245 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 245

Slide 246

Slide 246 text

class ObjectA { private objectB = new ObjectB(this); public method() { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 動作順序 把握できました? 246

Slide 247

Slide 247 text

ObjectA ObjectB methodForA methodForB methodForB2 methodForA2 methodForB3 methodForA3 methodForA4 247

Slide 248

Slide 248 text

ObjectA ObjectB methodForA methodForB methodForB2 methodForA2 methodForB3 methodForA3 methodForA4 把握できました? 248

Slide 249

Slide 249 text

どうするか? 249

Slide 250

Slide 250 text

ObjectA ObjectB 250

Slide 251

Slide 251 text

ObjectA ObjectB Parent ObjectA ObjectB 251

Slide 252

Slide 252 text

class Parent { private readonly objectA = new ObjectA(); private readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } 252

Slide 253

Slide 253 text

class Parent { private readonly objectA = new ObjectA(); private readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } class ObjectA { public methodForB() { ... } public methodForB2() { ... } public methodForB3() { ... } public methodForB4() { ... } } class ObjectB { public methodForA() { ... } public methodForA2() { ... } public methodForA3() { ... } public methodForA4() { ... } } 253

Slide 254

Slide 254 text

class Parent { private readonly objectA = new ObjectA(); private readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } class ObjectA { public methodForB() { ... } public methodForB2() { ... } public methodForB3() { ... } public methodForB4() { ... } } class ObjectB { public methodForA() { ... } public methodForA2() { ... } public methodForA3() { ... } public methodForA4() { ... } } オブジェクトは シンプルに 254

Slide 255

Slide 255 text

class Parent { private readonly objectA = new ObjectA(); private readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } 255

Slide 256

Slide 256 text

class Parent { private readonly objectA = new ObjectA(); private readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } コードを見れば 一目瞭然 256

Slide 257

Slide 257 text

コンポーネントも 同じ 257

Slide 258

Slide 258 text

TabButton TabButton TabButton TabButton 258

Slide 259

Slide 259 text

TabButton TabButton TabButton TabButton Click 259

Slide 260

Slide 260 text

TabButton TabButton TabButton TabButton Click Select 260

Slide 261

Slide 261 text

TabButton TabButton TabButton TabButton Click Select 261

Slide 262

Slide 262 text

TabButton TabButton TabButton TabButton Click unselect() Select 262

Slide 263

Slide 263 text

TabButton TabButton TabButton TabButton Click unselect() Select 263

Slide 264

Slide 264 text

TabButton TabButton TabButton TabButton Click unselect() Select 264

Slide 265

Slide 265 text

TabButton TabButton TabButton TabButton TabButtonGroup 265

Slide 266

Slide 266 text

TabButton TabButton TabButton TabButton TabButtonGroup Click 266

Slide 267

Slide 267 text

TabButton TabButton TabButton TabButton TabButtonGroup Click Clicked 267

Slide 268

Slide 268 text

TabButton TabButton TabButton TabButton TabButtonGroup Un Select Un Select Un Select Un Select 268

Slide 269

Slide 269 text

TabButton TabButton TabButton TabButton TabButtonGroup Un Select Un Select Un Select Un Select 269

Slide 270

Slide 270 text

TabButton TabButton TabButton TabButton TabButtonGroup Select 270

Slide 271

Slide 271 text

TabButton TabButton TabButton TabButton TabButtonGroup Select 271

Slide 272

Slide 272 text

TabButton TabButton TabButton TabButton TabContent Click 272

Slide 273

Slide 273 text

TabButton TabButton TabButton TabButton TabContent Clicked TabButtonGroup 273

Slide 274

Slide 274 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Clicked Clicked (B) Tab 274

Slide 275

Slide 275 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Un Select 275

Slide 276

Slide 276 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Un Select Un Select Un Select Un Select Un Select 276

Slide 277

Slide 277 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Un Select Un Select Un Select Un Select Un Select 277

Slide 278

Slide 278 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) 278

Slide 279

Slide 279 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) Select 279

Slide 280

Slide 280 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) Select 280

Slide 281

Slide 281 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Change Content 281

Slide 282

Slide 282 text

TabButton TabContent TabButtonGroup Tab 282

Slide 283

Slide 283 text

TabButton TabContent TabButtonGroup Tab 283

Slide 284

Slide 284 text

TabButton TabContent TabButtonGroup Tab メソッド 284

Slide 285

Slide 285 text

TabButton TabContent TabButtonGroup Tab メソッド 285

Slide 286

Slide 286 text

TabButton TabContent TabButtonGroup Tab メソッド イベント 286

Slide 287

Slide 287 text

TabButton TabContent TabButtonGroup Tab メソッド イベント コンポーネントの基本構造 287

Slide 288

Slide 288 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Clicked Tab Clicked (B) 288

Slide 289

Slide 289 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Clicked Tab イベント Clicked (B) 289

Slide 290

Slide 290 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) Select 290

Slide 291

Slide 291 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) Select メソッド 291

Slide 292

Slide 292 text

TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) Select メソッド Vue などでは これをバインディングで 実現する 292

Slide 293

Slide 293 text

たとえば 293

Slide 294

Slide 294 text

{{selected}} import {Component, Emit, Prop, Vue} from "vue-property-decorator"; @Component export default class TabButton extends Vue { @Prop() public selected!: boolean; @Emit('click') public onClick() { } } 294

Slide 295

Slide 295 text

{{selected}} import {Component, Emit, Prop, Vue} from "vue-property-decorator"; @Component export default class TabButton extends Vue { @Prop() public selected!: boolean; @Emit('click') public onClick() { } } 295

Slide 296

Slide 296 text

{{selected}} import {Component, Emit, Prop, Vue} from "vue-property-decorator"; @Component export default class TabButton extends Vue { @Prop() public selected!: boolean; @Emit('click') public onClick() { } } 296

Slide 297

Slide 297 text

    {{param.title}}
... export default class TabButtonGroup extends Vue { @Prop() public selectedTabId!: string; @Prop() public parameters!: ITabButtonParameter[]; @Emit('tabButtonClick') public onTabButtonClick(id: string) { } public isSelected(id: string) { return id === this.selectedTabId; } } 297

Slide 298

Slide 298 text

    {{param.title}}
... export default class TabButtonGroup extends Vue { @Prop() public selectedTabId!: string; @Prop() public parameters!: ITabButtonParameter[]; @Emit('tabButtonClick') public onTabButtonClick(id: string) { } public isSelected(id: string) { return id === this.selectedTabId; } } 298

Slide 299

Slide 299 text

    {{param.title}}
... export default class TabButtonGroup extends Vue { @Prop() public selectedTabId!: string; @Prop() public parameters!: ITabButtonParameter[]; @Emit('tabButtonClick') public onTabButtonClick(id: string) { } public isSelected(id: string) { return id === this.selectedTabId; } } 299

Slide 300

Slide 300 text

... export default class Tab extends Vue { public tabContents: TabContent[] = []; public selectedTab: TabContent | null = null; @Prop() public selectedTabId!: string; public mounted() { const tabContents = this.$slots.default .filter(x => x.componentInstance) .map(x => x.componentInstance) .map(x => x as TabContent); this.tabContents = tabContents; this.onTabGroupTabButtonClick(this.tabContents[0].id); } @Emit('tabButtonClick') public onTabGroupTabButtonClick(id: string) { } 300

Slide 301

Slide 301 text

... export default class Tab extends Vue { public tabContents: TabContent[] = []; public selectedTab: TabContent | null = null; @Prop() public selectedTabId!: string; public mounted() { const tabContents = this.$slots.default .filter(x => x.componentInstance) .map(x => x.componentInstance) .map(x => x as TabContent); this.tabContents = tabContents; this.onTabGroupTabButtonClick(this.tabContents[0].id); } @Emit('tabButtonClick') public onTabGroupTabButtonClick(id: string) { } 301

Slide 302

Slide 302 text

... export default class Tab extends Vue { public tabContents: TabContent[] = []; public selectedTab: TabContent | null = null; @Prop() public selectedTabId!: string; public mounted() { const tabContents = this.$slots.default .filter(x => x.componentInstance) .map(x => x.componentInstance) .map(x => x as TabContent); this.tabContents = tabContents; this.onTabGroupTabButtonClick(this.tabContents[0].id); } @Emit('tabButtonClick') public onTabGroupTabButtonClick(id: string) { } 302

Slide 303

Slide 303 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 303

Slide 304

Slide 304 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 304

Slide 305

Slide 305 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 305

Slide 306

Slide 306 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 306

Slide 307

Slide 307 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 307

Slide 308

Slide 308 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 308

Slide 309

Slide 309 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 子コンポーネント同士の 取り回しはあくまでも それを保持する親コンポーネントが 責任をもっておこなう 309

Slide 310

Slide 310 text

Vue logo ContentsFirst ContentsSecond ...
... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } 子コンポーネント同士が 勝手に反応しない ようにすること 310

Slide 311

Slide 311 text

コンポーネント構造のテーマ 1. コンポーネント構造 2. ページ遷移や通信を行う箇所 3. Flux 系のライブラリの使いどころ 4. データの保持は誰の役目? 311

Slide 312

Slide 312 text

ページ遷移 312

Slide 313

Slide 313 text

PageA PageB ComponentA Button 313

Slide 314

Slide 314 text

PageA PageB ComponentA Button Click 314

Slide 315

Slide 315 text

PageA PageB ComponentA Button Click 315

Slide 316

Slide 316 text

PageA PageB ComponentA Button 316

Slide 317

Slide 317 text

PageA PageB ComponentA Button 317

Slide 318

Slide 318 text

PageA PageB ComponentA Button Click 318

Slide 319

Slide 319 text

PageA PageB ComponentA Button Click 319

Slide 320

Slide 320 text

PageA PageB ComponentA Button Click 320

Slide 321

Slide 321 text

PageA PageB ComponentA Button 321

Slide 322

Slide 322 text

PageA PageB ComponentA Button ページ遷移は ページコンポーネントを見れば 分かるようにすること 322

Slide 323

Slide 323 text

PageA PageB Link Component これはページを見れば分かる (ページに遷移先情報がある) ので OK Parameter Link to PageB 323

Slide 324

Slide 324 text

通信 324

Slide 325

Slide 325 text

Page Component Data 325

Slide 326

Slide 326 text

Page Component Http Data 326

Slide 327

Slide 327 text

Page Component Http Http Data 327

Slide 328

Slide 328 text

Page Component Http Http コンポーネントの使いまわしがない限り 通信も基本はページ (データもページが保持してバインディング) Data 328

Slide 329

Slide 329 text

コンポーネント構造のテーマ 1. コンポーネント構造 2. ページ遷移や通信を行う箇所 3. Flux 系のライブラリの使いどころ 4. データの保持は誰の役目? 329

Slide 330

Slide 330 text

Flux は 複数のコンポーネントを 制御する目的で 使うのは控える 330

Slide 331

Slide 331 text

コンポーネントの基本構造に 従うことを優先する 331

Slide 332

Slide 332 text

コンポーネント構造のテーマ 1. コンポーネント構造 2. ページ遷移や通信を行う箇所 3. Flux 系のライブラリの使いどころ 4. データはどうやって変更する? 332

Slide 333

Slide 333 text

Component Component Data Component 333

Slide 334

Slide 334 text

Component Component Data Component Action 334

Slide 335

Slide 335 text

Component Component Data Component Action Event 335

Slide 336

Slide 336 text

Component Component Data Component Action Event Event 336

Slide 337

Slide 337 text

Component Component Data Component Action Event Event 337

Slide 338

Slide 338 text

Component Component Data Component Action Event Event データを変更するのは データを保持するコンポーネント 338

Slide 339

Slide 339 text

モデルバインディングは? 339

Slide 340

Slide 340 text

Message is: {{ message }}

340

Slide 341

Slide 341 text

Message is: {{ message }}

Component Input message 341

Slide 342

Slide 342 text

Message is: {{ message }}

Component Input message 342

Slide 343

Slide 343 text

Message is: {{ message }}

Component Input message 実はこうではない 343

Slide 344

Slide 344 text

Message is: {{ message }}

Component Input message 344

Slide 345

Slide 345 text

Message is: {{ message }}

Component Input message Event 345

Slide 346

Slide 346 text

Message is: {{ message }}

Component Input message Event 346

Slide 347

Slide 347 text

Message is: {{ message }}

Component Input message Event モデルバインディングは シンタックスシュガー 347

Slide 348

Slide 348 text

Agenda 1. GUIアーキテクチャパターン 2. データ同期 3. エラーハンドリング 4. コンポーネント構造 5. まとめ 348

Slide 349

Slide 349 text

シンプルなコードを 達成するための セオリー 349

Slide 350

Slide 350 text

350

Slide 351

Slide 351 text

ベクトルを意識 351

Slide 352

Slide 352 text

ベクトルを意識 データの流れ 実装の流れ 処理の流れ を一定にする 352

Slide 353

Slide 353 text

GUI プログラミングで 目指すべきゴール 353

Slide 354

Slide 354 text

Humble View 354

Slide 355

Slide 355 text

慎ましい View を 目指すこと 355

Slide 356

Slide 356 text

テストする必要もないほど 慎ましい View を 目指すこと 356

Slide 357

Slide 357 text

Auther Masanobu Naruse HomePage https://nrslib.com Twitter @nrslib