SlideShare a Scribd company logo
1 of 66
Download to read offline
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
はじめようVue3!

ハンズオンでとらのあなラボのフロントエンドを学ぶ



虎の穴ラボ 藤原 佳顕

1
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
アジェンダ

● 自己紹介

● なぜVue(3)か

● とらのあなラボでのVue(3)活用

● 今回利用する環境について

● TypeScriptについて(今回は割愛)

● Vue3ハンズオン

● まとめ

2
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
自己紹介

● 名前:藤原 佳顕

● 所属:虎の穴ラボ

● やっていること:(Fantia、)新規サービス、社内ツール、ソースレビュー

● 好きなもの:RustとかClojureとかDenoとか

● 好きなもの2:STG、音ゲー、格ゲー

3
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
なぜVue3か

● 一時期のフレームワークが群雄割拠していた時代に比べて、ほぼReact、Vue、Angularの
いずれかで安定している

● とはいえ、ライブラリ、フレームワーク自体のアップデートはそれなりに早い


○ ソースの記述が古くなる可能性が高い


○ 安定している or するだろうものであれば取り入れてしまったほうが良い


● 周辺ツールも同様の傾向

○ Vue3から推奨ツールがvue cli→viteに


4
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
虎の穴ラボでのVue(3)活用

5
● 新規プロジェクト(Nuxt.js)

● 社内の稼働時間管理ツール(Vue2→Vue3)

○ Vue2(Vue class component)からVue3にアップデート

● 社内のプロジェクト管理ツール(Vue3)

○ 作成段階からcomposition apiを利用
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
虎の穴ラボでのVue(3)活用

6
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
虎の穴ラボでのVue(3)活用

7
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
虎の穴ラボでのVue(3)活用

8
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
今回利用する環境

9
● macOS Big Sur

● TypeScript v4.1.3

● Node.js 14.17.0

○ これはインストールが必要です

○ docker用ファイルも用意してるのでそちらの利用でも構いません

● Vue 3.0.5

● Vite 2.3.3

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け

10
// 型はコロン(:)のあとに後置する形
// この関数はidという名前のnumber型の引数とnameという名前のstring型引数を取って、stringを返す関数
// ?がつく場合はオプションの引数となり渡さなくて良くなるが、関数内でチェックが必要
const hoge = (id: number, name: string, desc?: object): string => {
let keys: string[] = [];
if (desc) {
keys = Object.keys(desc);
}
return `id: ${id}, name: ${name}, desc_keys: ${keys}`;
};
// 型が推論できる場合は明示は不要
const a = 100;
const b = "toranoana";
// 型がわからないときは
any型になる(基本非推奨)
const c: any = { a: 123, b: { c: 200 } };
console.log(hoge(a, b));
// any型だとどこにでも入れられてしまう
console.log(hoge(a, b, c));
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け

11
// interfaceを使ってobjectなどに具体的な型を付けられる
interface Fuga {
ham: number;
spam: number;
storeName: string;
}
// interfaceを使った変数宣言 ?付きのオプションメンバー以外はすべてのメンバーが存在しないといけない
const meatStore: Fuga = { ham: 100, spam: 200, storeName: "駅前肉屋" };
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け

12
const meatMap = (store: Fuga) => {
console.log(`${store.storeName}にはhamが${store.ham}個、spamが${store.spam}個ありま
す。`);
}
meatMap(meatStore);
// ダックタイピングにより構造が一致してさえいれば呼び出せる
meatMap({ham: 1, spam: 2, storeName: "2丁目肉屋" });
// Type Aliasという機能もあるが、基本的には interfaceをベースに使ったほうが良い
// 長い名前に別名を付けたいときなどに利用
type FugaFuga = Fuga;
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け

13
// 特集な型その1:インデックスシグネチャ 以下は数値のキーに対して文字列のvalueが紐づくオブジェクトです
const ranking: { [key: number]: string } = { 1: "aさん" };
ranking[2] = "Bさん"; // ranking["3"] = "Bさん"; // keyにnumber以外を渡すとエラー
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
TypeScript:型付け

14
// 特集な型その2:ユニオン型
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle; // パイプ(|)で区切ることでAかBという型を表現できる
function menseki(s: Shape): number {
if (s.kind === "square") {
return s.size * s.size;
}
return s.width * s.height;
}
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ハンズオンについて

15
● メインの対象者

○ フロントエンドあまり触ったこと無い方

○ Vue2はやってたけどVue3のアップデートにあまり知らない方

● 目標

○ 実際にVue3でアプリを作るときに大抵のことでは困らなくて良くなる

● ソースコードはこちら 

○ https://github.com/toranoana/vue3-handson

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ブランチまたはディレクトリ名:資料の見方とサンプルの動かし方

16
● サンプルリポジトリを動かすには、以下の手順が必要です

○ package.jsonがあるディレクトリでnpm install 

○ package.jsonがあるディレクトリでnpm run dev

○ http://localhost:3000にアクセス

○ dockerの環境も用意してますので、詳細はREADMEをお読みください

● 以降ではタイトルの左側に現在作業中のディレクトリ名を表示します

○ リポジトリのディレクトリを参照してください

○ 実際に手を動かさない場合でも対象のディレクトリを参照していただくことで何をしているか
わかるかと思います
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
注意点と進め方

17
● 各ディレクトリで初回で動かす場合はディレクトリごとにnpm installが必要です


● 00.init_templateが初期状態のディレクトリです


○ こちらを拡張することでハンズオンを進めていきます


● ソースを手打ちしていただいても良いですが、各ディレクトリのサンプルをコピペしていただいても問題ないです


● ソース及び発表資料は公開いたしますので、途中でついていけなくなった方などは後日参照いただければと思い
ます

● 割愛させて頂く部分が発生するかもしれませんが、その際も公開された資料をご確認ください


● 今回は申し訳ありませんが、環境が動かない等のフォローはできない可能性があります。その際はソースの方を
追っていただければと思います


Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

18
1. コンポーネントの基本(basic_of_component) 

2. stateについて

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて←ここまでは実施予定 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
basic_of_component:コンポーネントの基本

19
● Vue.jsはWebコンポーネントとVirtual DOMを軸にしたフレームワークです

○ Reactや、Angular(2以降)と似たフレームワークです

● *.vueという拡張子のファイルが画面の1パーツ(コンポーネント)となります。以下例です

○ Button.vue:ボタンのコンポーネント

○ Header.vue:ヘッダーのコンポーネント

○ App.vue:Button.vueとHeader.vueを組み合わせて画面を作るコンポーネント
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue:ディレクトリ構成

20
❯ tree -L 2
.
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
├── src
│ ├── App.vue
│ ├── assets
│ ├── components
│ ├── main.ts
│ ├── router
│ ├── shims-vue.d.ts
│ ├── store
│ └── views
├── tsconfig.json
└── vite.config.ts
コンポーネントのエントリポイント
プログラムのエントリポイント
ルーティングに関するファイル置き場
*.vueファイルをTypeScriptに認識させるための型定義
Vuexに関するファイル置き場
URLと紐づくコンポーネントの置き場
小分けされたコンポーネント置き場
画像などの静的なファイル置き場
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
basic_of_component:コンポーネントの基本



21
<template>
<div id="app">
<div id="nav">
<!-- router/index.tsにかかれているルーティング情報から自動で
aタグを作る -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<!-- ルーティングされたコンポーネントがここに描画される-->
<router-view />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "App",
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
basic_of_component:コンポーネントの基本



22
App.vue

router-link x 2

router-view

HelloWorld.vue

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
23
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

24
1. コンポーネントの基本 

2. stateについて(state) 

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
state:stateについて

● setupメソッド

○ 各コンポーネントのエントリポイントとなるメソッド 

○ 呼ばれた段階ではまだレンダリングされていない状態 

● reactive関数

○ リアクティブなオブジェクトを作成できる 

○ リアクティブな状態が変化するとビューが自動的に更新される 

○ state.messageを更新すると、template側でstate.messageを使ってる部分も自動で変わる(後述) 

25
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
state:stateについて

<template>
<div id="app">
<div id="nav">
<!-- 追加 -->
<p>{{ state.message }}</p>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>
26
<script lang="ts">
import { defineComponent, reactive } from "vue";
interface State {
message: string;
}
export default defineComponent({
name: "App",
setup() {
const state = reactive<State>({
message: "Hello Sample"
});
return { state };
}
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
state:stateについて

一番上に”Hello Sample”が追
加される

27
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

28
1. コンポーネントの基本 

2. stateについて

3. イベントについて(event) 

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて

<template>
<div id="app">
<div id="nav">
<p>{{state.message}}</p>
<!-- 追加 -->
<p>
<button type="button" @click="onClick">メッセージを変更 </button>
</p>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template 29
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて
 export default defineComponent({
name: "App",
setup() {
const state = reactive<State>({
message: "Hello Sample"
});
// 追加
const onClick = () => {
state.message = "clicked";
};
return {
state,
// 追加
onClick
};
}
}); 30
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて

● 関数の作り方

○ setup関数内で関数を作り、戻り値として返す 

○ template内で@clickなどで関数をイベントを紐付けする 

○ reactiveな値と共に別ファイルに書くこともできる(次ページ) 

● 表示の更新について 

○ reactiveで生成した変数を、関数内で更新すると自動でtemplate内の表示も変わる 

○ element.innerHTMLなどを利用した直接的なDOM書き換えは不要
31
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
event:イベントについて

import { AppState, useAppState } from './utils';
type State = AppState
export default defineComponent({
name: "App",
components: { Sample, Async },
setup() {
const [state, onClick] = useAppState();
return {
state,
onClick
};
}
});
32
reactiveな値と、値を変更する処理を別ファイルに書くこともでき る例(utils.ts)







import { reactive } from "vue";
export interface AppState {
message: string;
}
export const useAppState = (): [AppState, () => void] => {
const state = reactive<AppState>({
message: "Hello Sample",
});
const onClick = () => {
state.message = "clicked";
};
return [state, onClick];
};
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

33
1. コンポーネントの基本 

2. stateについて

3. イベントについて

4. コンポーネント間の連携(component_props) 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_props:コンポーネント間の連携






34
components/Sample.vueを作成

<script lang="ts">
import { defineComponent } from "vue"
interface State {
localMessage: string;
}
export default defineComponent({
props: {
parentMessage: {
type: String,
required: true,
},
},
setup() {
const state = reactive<State>({ localMessage: "child component" });
return { state };
},
});
</ script>
<template>
<div>
<p>localMessage: {{ state.localMessage }}</p>
<p>parentMessage: {{ parentMessage }}</p>
</div>
</template>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_props:コンポーネント間の連携

<template>
<div id="app">
<div id="nav">
<!-- 追加 -->
<sample :parent-message="state.message" />
<!-- <p>{{ state.message }}</p> -->
<!-- 以下略 -->
</template>
35
<script lang="ts">
import { defineComponent, reactive } from "vue";
import Sample from './components/Sample.vue';
interface State {
message: string;
}
export default defineComponent({
name: "App",
// 追加
components: { Sample },
// 以下略
});
</script>
App.vueを変更

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_props:コンポーネント間の連携

● props

○ 親コンポーネントから渡ってくるデータ。変更不可 

■ 変更したい場合は変更用の処理を一緒に渡す(後述) 

○ プリミティブな値だけでなく、objectや関数も渡せる 

● 子コンポーネントの埋め込み方 

○ defineComponent内にcomponentsプロパティを追加 

○ template内でカスタムタグのように子コンポーネントを埋め込み 

● propsの渡し方について 

○ :`props名` で受け渡す 

■ v-bind:`prps名` のシンタックスシュガー
36
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue:コンポーネント間の連携

37
子コンポーネント(Sample.vue)内で親(App.vue)から渡された
propsが表示される





親での変更がpropsにも反映され、表示が変わる

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

38
1. コンポーネントの基本 

2. stateについて

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更、component_events) 

6. ライフサイクルについて 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)



39
Sample.vueを変更

<template>
<div>
<p>localMessage: {{ state.localMessage }}</p>
<p>parentMessage: {{ parentMessage }}</p>
</div>
<!-- 以下追加 -->
<p>
<button type="button" @click="updateMessage">propで更新</button>
</p>
<p>
<button type="button" @click="emitClick">emitで更新</button>
</p>
</template>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)



40
Sample.vueを変更

propsで変更用の関数を受け取る場合と、Eventで受け取る場合を追加

<script lang="ts">
// 略
export default defineComponent({
props: {
// 略
// 追加(propsで変更用の関数を受け取るケース
)
updateMessage: {
type: Function as PropType<() => void>,
default: () => {},
},
},
emits: ["click"],
setup(_, { emit }: SetupContext) {
// 略
// 追加(Eventとして変更用の関数を受け取るケース
)
const emitClick = () => {
emit("click");
};
return {
state,
emitClick, // 追加
};
},
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)



41
App.vueを変更

propsとEventを渡すようにする

<template>
<div id="app">
<div id="nav">
<!-- 追加(propsと@click) -->
<sample
:parent-message="state.message"
@click="onChildEmit"
:update-message="onChildClick"
/>
<!-- 以下略 -->
</template>
<script lang="ts">
// 略
export default defineComponent({
// 略
setup() {
// 略
// 追加(2つ)
const onChildClick = () => { state.message = "child clicked"; };
const onChildEmit = () => { state.message = "child emit clicked"; };
return {
state, onClick,
// 追加(2つ)
onChildClick,
onChildEmit,
};
},
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)



42
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
component_events:コンポーネント間の連携その2(propsの変更)



● propsとして関数受け渡し 

○ typeにFunctionを指定することでpropsとして関数を受け取れるようにする 

○ 関数の具体的な型はPropTypeを使うことで明示できる 

● Eventとしての関数受け渡し 

○ defineComponentのプロパティとしてemitsを追加(Vue3から) 

■ 呼び出す可能性のあるEvent一覧を文字列で追加 

■ objectで指定することで引数等のバリデーションも可能(今回は割愛) 

○ setup関数の第二引数、SetupContextのメンバーとしてemit関数がある 

○ emit(`呼びたいEvent名`, `引数`)で関数呼び出しできる 

■ 文字列で関数を呼び出すため具体的な型がつけにくい
43
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

44
1. コンポーネントの基本 

2. stateについて

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて(lifecycle) 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
lifecycle:ライフサイクルについて
● ReactやAngularなどと同様にライフサイクルがあります 

○ https://v3.vuejs.org/guide/composition-api-lifecycle-hooks.html 

○ Vue2であったcreatedはsetupに統合されました 

● よく使うもの

○ mounted

■ DOMに触れられるようになったタイミングで発火 

○ unmounted

■ コンポーネントが破棄されるとき 

■ windowに何かしらイベント付けてるときの破棄などに使う(メモリリーク防止) 

45
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
lifecycle:ライフサイクルについて

46
views/Home.vueを変更

<script lang="ts">
// ライフサイクルのHookメソッドを追加
import { defineComponent, onMounted, onUnmounted } from "vue";
import HelloWorld from "../components/HelloWorld.vue";
export default defineComponent({
// 略
// setupメソッド追加
setup() {
const resizeEvent = () => { console.log("resize window"); };
onMounted(() => {
window.addEventListener("resize", resizeEvent);
});
onUnmounted(() => {
window.removeEventListener("resize", resizeEvent);
});
},
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
47
Aboutページに行くとリサイズイベントが止まる 

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

48
1. コンポーネントの基本 

2. stateについて

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて 

7. 非同期通信(ajax)

8. computedとwatch

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
● 生のXMLHttpRequestやfetch APIも使えますが、今回はライブラリを利用します 

○ https://github.com/axios/axios 

○ npm install axios @types/axios 

○ サンプルのリポジトリにはインストール済みです 

○ コンポーネントマウント前にデータ取得開始→state変更といった流れにします 

49
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)


50
● 今回はBitCoinの金額を取得するAPIを利用します(coindesk api)

○ https://api.coindesk.com/v1/bpi/currentprice.json

APIのレスポンスの型は次のものを想定

interface Time {
updated: string;
updatedISO: string;
updateduk: string;
}
interface Bpi {
code: string;
symbol: string;
rate: string;
description: string;
rate_float: number;
}
interface CurrentPrice {
time: Time;
disclaimer: string;
chartName: string;
bpi: {
USD: Bpi;
GBP: Bpi;
EUR: Bpi;
};
}
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)


51
components/Async.vueを作成

<template>
<pre v-if="state.apiData">
<code>
{{ state.apiData }}
</code>
</pre>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
import axios from "axios";
// APIのinterfaceは略(前ページ参照)
interface State {
apiData: CurrentPrice | null;
}
export default defineComponent({
setup() {
const state = reactive<State>({ apiData: null });
axios
.get<CurrentPrice>("https://api.coindesk.com/v1/bpi/currentprice.json")
.then((res) => { state.apiData = res.data; });
return { state, };
},
});
</script>
<style scoped>
pre {
height: 300px;
overflow: scroll;
border: solid 1px #8a8a8a;
}
</style>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)


52
App.vueに追記

<template>
<div id="app">
<div id="nav">
<!-- 略 -->
<async />
<!-- 略 →
</div>
<router-view />
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, reactive } from "vue";
import Sample from "./components/Sample.vue";
// 追加
import Async from "./components/Async.vue";
interface State {
message: string;
}
export default defineComponent({
name: "App",
// Async追加
components: { Sample, Async },
// 略
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue:非同期通信(Ajax)


53
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajaxおまけ)


54
setup関数をasyncにしたい場合(Async.vue)

export default defineComponent({
async setup() {
const state = reactive<State>({ apiData: null });
const res = await axios.get<CurrentPrice>("https://api.coindesk.com/v1/bpi/currentprice.json");
state.apiData = res.data;
return {
state,
};
},
});
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajaxおまけ)


55
App.vueでAsyncコンポーネントをSuspenseで囲む

<template>
<!-- 略 -->
<!-- 追加:Supenseで囲むことで非同期コンポーネントのフォールバックコンテンツを表示
-->
<Suspense>
<template #default>
<async />
</template>
<template #fallback>
<div>loading...</div>
</template>
</Suspense>
<!-- 略 -->
</template>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
ajax:非同期通信(Ajax)
● async setupとする場合はSuspenseが必要 

○ https://v3.ja.vuejs.org/guide/migration/suspense.html 

● Suspense自体は非同期コンポーネントの描画を待つ間、代わりを表示する機能 

○ Suspenseなしasync setupなコンポーネントの部分は何も描画されなくなります 

● Vue2でのasync createdのつもりで使うと引っかかるかもしれないので注意 

56
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

57
1. コンポーネントの基本 

2. stateについて

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて 

7. 非同期通信(Ajax)

8. computedとwatch(computed_and_watch) 

9. ルーティング

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
computed_and_watch:computedとwatch


58
Sample.vueに追記

<div>
<!-- 以下2つに変更 -->
<p>{{ localFullMessage }}</p>
<p>{{ parentFullMessage }}</p>
</div>
<p>
<button type="button" @click="updateMessage">propで更新</button>
</p>
<p>
<button type="button" @click="emitClick">emitで更新</button>
</p>
</template>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
computed_and_watch:computedとwatch


59
// computedとwatchとwatchEffect追加
import { computed, watch, watchEffect, /* 略 */ } from "vue";
// 略
export default defineComponent({
// 略、propsをsetupの引数に追加
setup(props, { emit }: SetupContext) {
const state = reactive<State>({
localMessage: "child component"
});
// 以下色々追加
const localFullMessage = computed(
() => `localMessage: ${state.localMessage}`
);
const parentFullMessage = computed(
() => `parentMessage: ${props.parentMessage}`
);
watchEffect(() => {
alert(
`localMessageかparentMessageが変更されました。
${localFullMessage.value}
${parentFullMessage.value}`
);
});
watch(
() => props.parentMessage,
() => alert("parentMessageが変更されました。 ")
);
const emitClick = () => { emit("click"); };
return {
// 追加(localFullMessage、parentFullMessage)
state, emitClick, localFullMessage, parentFullMessage,
};
},
});
</script>
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
computed_and_watch:computedとwatch

● watch、watchEffectを使うことでデータの監視が可能 

○ watchEffect:コールバックに指定した関数の中で使ってるリアクティブな変数が変更されたら関数
を再度実行する

○ watch:第一引数に指定した変数が変更されたら第2引数の関数を再度実行する 

● computedを使うことでデータに加工が可能 

○ 不変でreactiveなrefオブジェクトを返す関数 

○ computed内で使ってる変数が変更されると戻り値もリアクティブに変更される 

60
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
vue

61
1. コンポーネントの基本 

2. stateについて

3. イベントについて

4. コンポーネント間の連携 

5. コンポーネント間の連携その2(propsの変更) 

6. ライフサイクルについて 

7. 非同期通信(Ajax)

8. computedとwatch

9. ルーティング(routing) 

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
routing:ルーティング 





62
<template>
<div>Topページ</div>
<Suspense>
<template #default>
<async />
</template>
<template #fallback>
<div>loading...</div>
</template>
</Suspense>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Async from "../components/Async.vue";
export default defineComponent({
components: { Async },
});
</script>
URLとコンポーネントを紐付けるために、views/Top.vueを作成 

中身では先程作成したAsync.vueを表示してみます 

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
routing:ルーティング 





63
// 略
const routes: RouteRecordRaw[] = [
{ path: '/', component: Home },
{ path: '/about', component: About },
// 追加
{ path: '/top', component: Top },
];
export const router = createRouter({
history: createWebHistory(),
routes,
});
<template>
<div id="app">
<div id="nav">
<!-- 略 -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<!-- 追加 -->
<router-link to="/top">Top</router-link>
</div>
<router-view />
</div>
</template>
続いて、router/index.tsとApp.vueを変更 

(router/index.ts)

(App.vue)

Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
64
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
routing:ルーティング 

65
● 各パスに1コンポーネントが紐づく形になります 

○ 指定したコンポーネントがApp.vueの<router-view />に入ります 

● コンポーネントを非同期ロードすることも可能 

○ ダイナミックインポートしたコンポーネントをパスに紐付ける 

○ 画面ロード時のファイルサイズを小さくすることができる 

{ path: '/top', component: () => import(/* webpackChunkName: "top" */ '../views/Top.vue') },
Copyright  (C) 2021 Toranoana Inc. All Rights Reserved.
まとめ

66
● Vue3と各機能について説明しました 

○ 単一コンポーネント内で完結するstateと更新処理について説明しました 

○ propsやeventを通したコンポーネント間の連携について説明しました 

○ Vue3は昨年リリースされたばかりの新しいフレームワークです 

○ Vue3での実際のアプリケーションの使い方について説明しました 

○ 説明してませんが、周辺ライブラリがVue3の記述に追いついてない場合があるので注意 

○ 公開するスライドには説明しなかった部分も含まれるのでぜひ見てみてください 


More Related Content

What's hot

What's hot (20)

【20220120 toranoana.deno#4】denoでffiの続き
【20220120 toranoana.deno#4】denoでffiの続き【20220120 toranoana.deno#4】denoでffiの続き
【20220120 toranoana.deno#4】denoでffiの続き
 
【とらのあなラボ Tech Day #3】新規システムにおける技術選定〜GoとgRPCを採用した話〜
【とらのあなラボ Tech Day #3】新規システムにおける技術選定〜GoとgRPCを採用した話〜	【とらのあなラボ Tech Day #3】新規システムにおける技術選定〜GoとgRPCを採用した話〜
【とらのあなラボ Tech Day #3】新規システムにおける技術選定〜GoとgRPCを採用した話〜
 
Amplify Studioを使ってみた
Amplify Studioを使ってみたAmplify Studioを使ってみた
Amplify Studioを使ってみた
 
Deno を aws fargate で動かす
Deno を aws fargate で動かすDeno を aws fargate で動かす
Deno を aws fargate で動かす
 
通販開発部の西田さん「通販開発マネジメントの5ルール」
通販開発部の西田さん「通販開発マネジメントの5ルール」通販開発部の西田さん「通販開発マネジメントの5ルール」
通販開発部の西田さん「通販開発マネジメントの5ルール」
 
サーバサイドKotlinへの入門 Ktor編
サーバサイドKotlinへの入門 Ktor編サーバサイドKotlinへの入門 Ktor編
サーバサイドKotlinへの入門 Ktor編
 
仕事部屋の温度管理をLambdaで実施した話
仕事部屋の温度管理をLambdaで実施した話仕事部屋の温度管理をLambdaで実施した話
仕事部屋の温度管理をLambdaで実施した話
 
2018/2/20 Kotlin勉強会
2018/2/20 Kotlin勉強会2018/2/20 Kotlin勉強会
2018/2/20 Kotlin勉強会
 
iOSレガシーコード改善ガイド〜マンガボックス開発における事例〜
iOSレガシーコード改善ガイド〜マンガボックス開発における事例〜iOSレガシーコード改善ガイド〜マンガボックス開発における事例〜
iOSレガシーコード改善ガイド〜マンガボックス開発における事例〜
 
FINAL FANTASY
 Record Keeper アニメーション制作の濃ゆい話
FINAL FANTASY
 Record Keeper アニメーション制作の濃ゆい話FINAL FANTASY
 Record Keeper アニメーション制作の濃ゆい話
FINAL FANTASY
 Record Keeper アニメーション制作の濃ゆい話
 
Use JWT access-token on Grails REST API
Use JWT access-token on Grails REST APIUse JWT access-token on Grails REST API
Use JWT access-token on Grails REST API
 
Quiznowを支える技術 #yapcasia
Quiznowを支える技術 #yapcasiaQuiznowを支える技術 #yapcasia
Quiznowを支える技術 #yapcasia
 
DeNAのゲーム開発を支える技術 (クライアントサイド編)
DeNAのゲーム開発を支える技術 (クライアントサイド編)DeNAのゲーム開発を支える技術 (クライアントサイド編)
DeNAのゲーム開発を支える技術 (クライアントサイド編)
 
Effective web performance tuning for smartphone
Effective web performance tuning for smartphoneEffective web performance tuning for smartphone
Effective web performance tuning for smartphone
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
 
QuizNow yapcasia
QuizNow yapcasiaQuizNow yapcasia
QuizNow yapcasia
 
FINAL FANTASY Record Keeperのマスターデータを支える技術
FINAL FANTASY Record Keeperのマスターデータを支える技術FINAL FANTASY Record Keeperのマスターデータを支える技術
FINAL FANTASY Record Keeperのマスターデータを支える技術
 
チラシルiOSでの広告枠開発
チラシルiOSでの広告枠開発チラシルiOSでの広告枠開発
チラシルiOSでの広告枠開発
 
社内ツールが支えるドリコムの社内勉強会文化 #metabenkyokai
社内ツールが支えるドリコムの社内勉強会文化 #metabenkyokai社内ツールが支えるドリコムの社内勉強会文化 #metabenkyokai
社内ツールが支えるドリコムの社内勉強会文化 #metabenkyokai
 
FINAL FANTASY Record Keeper の作り方
FINAL FANTASY Record Keeper の作り方FINAL FANTASY Record Keeper の作り方
FINAL FANTASY Record Keeper の作り方
 

Similar to はじめようVue3!ハンズオンでとらのあなラボのフロントエンドを学ぶ_20210611_TechDay#1

UnityとnodeとMMDと
UnityとnodeとMMDとUnityとnodeとMMDと
UnityとnodeとMMDと
sters
 
初心者向けAndroidゲーム開発ノウハウ
初心者向けAndroidゲーム開発ノウハウ初心者向けAndroidゲーム開発ノウハウ
初心者向けAndroidゲーム開発ノウハウ
Kentarou Mukunasi
 
TokyoR24 - PerformanceRvsC#
TokyoR24 - PerformanceRvsC#TokyoR24 - PerformanceRvsC#
TokyoR24 - PerformanceRvsC#
ta2c
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
えぴ 福田
 

Similar to はじめようVue3!ハンズオンでとらのあなラボのフロントエンドを学ぶ_20210611_TechDay#1 (20)

インターネットプログラミング 解説資料
インターネットプログラミング 解説資料インターネットプログラミング 解説資料
インターネットプログラミング 解説資料
 
「AROW」お披露目(実用編)
「AROW」お披露目(実用編)「AROW」お披露目(実用編)
「AROW」お披露目(実用編)
 
DeNA TechCon2016 360VR Live Streaming
DeNA TechCon2016 360VR Live StreamingDeNA TechCon2016 360VR Live Streaming
DeNA TechCon2016 360VR Live Streaming
 
Deno で始めるフロントエンド
Deno で始めるフロントエンドDeno で始めるフロントエンド
Deno で始めるフロントエンド
 
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
 
FFRK cocos2d xレイヤーの最適化
FFRK cocos2d xレイヤーの最適化FFRK cocos2d xレイヤーの最適化
FFRK cocos2d xレイヤーの最適化
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
革新的ブラウザゲームを支えるプラットフォーム技術
革新的ブラウザゲームを支えるプラットフォーム技術革新的ブラウザゲームを支えるプラットフォーム技術
革新的ブラウザゲームを支えるプラットフォーム技術
 
UnityとnodeとMMDと
UnityとnodeとMMDとUnityとnodeとMMDと
UnityとnodeとMMDと
 
C#の書き方
C#の書き方C#の書き方
C#の書き方
 
C#の書き方
C#の書き方C#の書き方
C#の書き方
 
初心者向けAndroidゲーム開発ノウハウ
初心者向けAndroidゲーム開発ノウハウ初心者向けAndroidゲーム開発ノウハウ
初心者向けAndroidゲーム開発ノウハウ
 
Windows 11とNPUで実現するWindowsのAI
Windows 11とNPUで実現するWindowsのAIWindows 11とNPUで実現するWindowsのAI
Windows 11とNPUで実現するWindowsのAI
 
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
 
ngCore engine for mobage platform
ngCore engine for mobage platformngCore engine for mobage platform
ngCore engine for mobage platform
 
Houdini Alembic を使ったライティングワークフロー
Houdini Alembic を使ったライティングワークフローHoudini Alembic を使ったライティングワークフロー
Houdini Alembic を使ったライティングワークフロー
 
Groovy Bootcamp 2015 by JGGUG
Groovy Bootcamp 2015 by JGGUGGroovy Bootcamp 2015 by JGGUG
Groovy Bootcamp 2015 by JGGUG
 
TokyoR24 - PerformanceRvsC#
TokyoR24 - PerformanceRvsC#TokyoR24 - PerformanceRvsC#
TokyoR24 - PerformanceRvsC#
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
 
Androidプログラミング初心者のためのゲームアプリ開発入門
Androidプログラミング初心者のためのゲームアプリ開発入門Androidプログラミング初心者のためのゲームアプリ開発入門
Androidプログラミング初心者のためのゲームアプリ開発入門
 

More from 虎の穴 開発室

More from 虎の穴 開発室 (20)

FizzBuzzで学ぶJavaの進化
FizzBuzzで学ぶJavaの進化FizzBuzzで学ぶJavaの進化
FizzBuzzで学ぶJavaの進化
 
Railsのデバッグ どうやるかを改めて確認する
Railsのデバッグ どうやるかを改めて確認するRailsのデバッグ どうやるかを改めて確認する
Railsのデバッグ どうやるかを改めて確認する
 
虎の穴ラボ エンジニア採用説明資料 .pdf
虎の穴ラボ エンジニア採用説明資料 .pdf虎の穴ラボ エンジニア採用説明資料 .pdf
虎の穴ラボ エンジニア採用説明資料 .pdf
 
Deno Deployと組み合わせるのに Upstashをおすすめしたい.pdf
Deno Deployと組み合わせるのに Upstashをおすすめしたい.pdfDeno Deployと組み合わせるのに Upstashをおすすめしたい.pdf
Deno Deployと組み合わせるのに Upstashをおすすめしたい.pdf
 
toranoana.deno #6 アジェンダ 採用説明
toranoana.deno #6 アジェンダ 採用説明toranoana.deno #6 アジェンダ 採用説明
toranoana.deno #6 アジェンダ 採用説明
 
Deno 向け WEB 開発用のツールを作ったので 紹介します
Deno 向け WEB 開発用のツールを作ったので 紹介しますDeno 向け WEB 開発用のツールを作ったので 紹介します
Deno 向け WEB 開発用のツールを作ったので 紹介します
 
Supabase Edge Functions と Netlify Edge Functions を使ってみる – 機能とその比較 –
Supabase Edge Functions と Netlify Edge Functions を使ってみる – 機能とその比較 –Supabase Edge Functions と Netlify Edge Functions を使ってみる – 機能とその比較 –
Supabase Edge Functions と Netlify Edge Functions を使ってみる – 機能とその比較 –
 
GCPの画像認識APIの紹介
GCPの画像認識APIの紹介 GCPの画像認識APIの紹介
GCPの画像認識APIの紹介
 
【エンジニアの勉強法ハックLT- vol.7】ゲームから学んだ勉強のこと
【エンジニアの勉強法ハックLT- vol.7】ゲームから学んだ勉強のこと【エンジニアの勉強法ハックLT- vol.7】ゲームから学んだ勉強のこと
【エンジニアの勉強法ハックLT- vol.7】ゲームから学んだ勉強のこと
 
社内DX推進!非エンジニア向けにプログラミング講座を実施してみた!
社内DX推進!非エンジニア向けにプログラミング講座を実施してみた!社内DX推進!非エンジニア向けにプログラミング講座を実施してみた!
社内DX推進!非エンジニア向けにプログラミング講座を実施してみた!
 
セキュリティを強化しよう!CloudArmorの機能解説
セキュリティを強化しよう!CloudArmorの機能解説セキュリティを強化しよう!CloudArmorの機能解説
セキュリティを強化しよう!CloudArmorの機能解説
 
いいテスト会 (スプリントレビュー) をやろう!
いいテスト会 (スプリントレビュー) をやろう!いいテスト会 (スプリントレビュー) をやろう!
いいテスト会 (スプリントレビュー) をやろう!
 
虎の穴ラボ Tech day#3 チームで戦う!とらのあな通販冬の大感謝祭でのフロント開発について
虎の穴ラボ Tech day#3 チームで戦う!とらのあな通販冬の大感謝祭でのフロント開発について虎の穴ラボ Tech day#3 チームで戦う!とらのあな通販冬の大感謝祭でのフロント開発について
虎の穴ラボ Tech day#3 チームで戦う!とらのあな通販冬の大感謝祭でのフロント開発について
 
虎の穴ラボ TechDay#3 フルリモート率100%!リモートワークを可能にするマネージメント
虎の穴ラボ TechDay#3 フルリモート率100%!リモートワークを可能にするマネージメント 虎の穴ラボ TechDay#3 フルリモート率100%!リモートワークを可能にするマネージメント
虎の穴ラボ TechDay#3 フルリモート率100%!リモートワークを可能にするマネージメント
 
【20220120 toranoana.deno#4】deno を使って「ログイン」するサービスを作る
【20220120 toranoana.deno#4】deno を使って「ログイン」するサービスを作る【20220120 toranoana.deno#4】deno を使って「ログイン」するサービスを作る
【20220120 toranoana.deno#4】deno を使って「ログイン」するサービスを作る
 
虎の穴ラボ エンジニア採用説明資料
虎の穴ラボ エンジニア採用説明資料 虎の穴ラボ エンジニア採用説明資料
虎の穴ラボ エンジニア採用説明資料
 
虎の穴ラボにおけるリモートワークの働き方
虎の穴ラボにおけるリモートワークの働き方虎の穴ラボにおけるリモートワークの働き方
虎の穴ラボにおけるリモートワークの働き方
 
【コードレビューLT資料】コード規約の策定会を実施した話
【コードレビューLT資料】コード規約の策定会を実施した話【コードレビューLT資料】コード規約の策定会を実施した話
【コードレビューLT資料】コード規約の策定会を実施した話
 
ワーケーションを 体験してみて〜富山 ワーケーションモニターツアーに参加しました
ワーケーションを 体験してみて〜富山 ワーケーションモニターツアーに参加しましたワーケーションを 体験してみて〜富山 ワーケーションモニターツアーに参加しました
ワーケーションを 体験してみて〜富山 ワーケーションモニターツアーに参加しました
 
はじめてのわーけーしょん
はじめてのわーけーしょんはじめてのわーけーしょん
はじめてのわーけーしょん
 

Recently uploaded

Recently uploaded (11)

Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 

はじめようVue3!ハンズオンでとらのあなラボのフロントエンドを学ぶ_20210611_TechDay#1

  • 1. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. はじめようVue3!
 ハンズオンでとらのあなラボのフロントエンドを学ぶ
 
 虎の穴ラボ 藤原 佳顕
 1
  • 2. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. アジェンダ
 ● 自己紹介
 ● なぜVue(3)か
 ● とらのあなラボでのVue(3)活用
 ● 今回利用する環境について
 ● TypeScriptについて(今回は割愛)
 ● Vue3ハンズオン
 ● まとめ
 2
  • 3. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 自己紹介
 ● 名前:藤原 佳顕
 ● 所属:虎の穴ラボ
 ● やっていること:(Fantia、)新規サービス、社内ツール、ソースレビュー
 ● 好きなもの:RustとかClojureとかDenoとか
 ● 好きなもの2:STG、音ゲー、格ゲー
 3
  • 4. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. なぜVue3か
 ● 一時期のフレームワークが群雄割拠していた時代に比べて、ほぼReact、Vue、Angularの いずれかで安定している
 ● とはいえ、ライブラリ、フレームワーク自体のアップデートはそれなりに早い 
 ○ ソースの記述が古くなる可能性が高い 
 ○ 安定している or するだろうものであれば取り入れてしまったほうが良い 
 ● 周辺ツールも同様の傾向
 ○ Vue3から推奨ツールがvue cli→viteに 
 4
  • 5. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 虎の穴ラボでのVue(3)活用
 5 ● 新規プロジェクト(Nuxt.js)
 ● 社内の稼働時間管理ツール(Vue2→Vue3)
 ○ Vue2(Vue class component)からVue3にアップデート
 ● 社内のプロジェクト管理ツール(Vue3)
 ○ 作成段階からcomposition apiを利用
  • 6. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 虎の穴ラボでのVue(3)活用
 6
  • 7. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 虎の穴ラボでのVue(3)活用
 7
  • 8. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 虎の穴ラボでのVue(3)活用
 8
  • 9. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 今回利用する環境
 9 ● macOS Big Sur
 ● TypeScript v4.1.3
 ● Node.js 14.17.0
 ○ これはインストールが必要です
 ○ docker用ファイルも用意してるのでそちらの利用でも構いません
 ● Vue 3.0.5
 ● Vite 2.3.3

  • 10. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. TypeScript:型付け
 10 // 型はコロン(:)のあとに後置する形 // この関数はidという名前のnumber型の引数とnameという名前のstring型引数を取って、stringを返す関数 // ?がつく場合はオプションの引数となり渡さなくて良くなるが、関数内でチェックが必要 const hoge = (id: number, name: string, desc?: object): string => { let keys: string[] = []; if (desc) { keys = Object.keys(desc); } return `id: ${id}, name: ${name}, desc_keys: ${keys}`; }; // 型が推論できる場合は明示は不要 const a = 100; const b = "toranoana"; // 型がわからないときは any型になる(基本非推奨) const c: any = { a: 123, b: { c: 200 } }; console.log(hoge(a, b)); // any型だとどこにでも入れられてしまう console.log(hoge(a, b, c));
  • 11. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. TypeScript:型付け
 11 // interfaceを使ってobjectなどに具体的な型を付けられる interface Fuga { ham: number; spam: number; storeName: string; } // interfaceを使った変数宣言 ?付きのオプションメンバー以外はすべてのメンバーが存在しないといけない const meatStore: Fuga = { ham: 100, spam: 200, storeName: "駅前肉屋" };
  • 12. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. TypeScript:型付け
 12 const meatMap = (store: Fuga) => { console.log(`${store.storeName}にはhamが${store.ham}個、spamが${store.spam}個ありま す。`); } meatMap(meatStore); // ダックタイピングにより構造が一致してさえいれば呼び出せる meatMap({ham: 1, spam: 2, storeName: "2丁目肉屋" }); // Type Aliasという機能もあるが、基本的には interfaceをベースに使ったほうが良い // 長い名前に別名を付けたいときなどに利用 type FugaFuga = Fuga;
  • 13. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. TypeScript:型付け
 13 // 特集な型その1:インデックスシグネチャ 以下は数値のキーに対して文字列のvalueが紐づくオブジェクトです const ranking: { [key: number]: string } = { 1: "aさん" }; ranking[2] = "Bさん"; // ranking["3"] = "Bさん"; // keyにnumber以外を渡すとエラー
  • 14. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. TypeScript:型付け
 14 // 特集な型その2:ユニオン型 interface Square { kind: "square"; size: number; } interface Rectangle { kind: "rectangle"; width: number; height: number; } type Shape = Square | Rectangle; // パイプ(|)で区切ることでAかBという型を表現できる function menseki(s: Shape): number { if (s.kind === "square") { return s.size * s.size; } return s.width * s.height; }
  • 15. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ハンズオンについて
 15 ● メインの対象者
 ○ フロントエンドあまり触ったこと無い方
 ○ Vue2はやってたけどVue3のアップデートにあまり知らない方
 ● 目標
 ○ 実際にVue3でアプリを作るときに大抵のことでは困らなくて良くなる
 ● ソースコードはこちら 
 ○ https://github.com/toranoana/vue3-handson

  • 16. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ブランチまたはディレクトリ名:資料の見方とサンプルの動かし方
 16 ● サンプルリポジトリを動かすには、以下の手順が必要です
 ○ package.jsonがあるディレクトリでnpm install 
 ○ package.jsonがあるディレクトリでnpm run dev
 ○ http://localhost:3000にアクセス
 ○ dockerの環境も用意してますので、詳細はREADMEをお読みください
 ● 以降ではタイトルの左側に現在作業中のディレクトリ名を表示します
 ○ リポジトリのディレクトリを参照してください
 ○ 実際に手を動かさない場合でも対象のディレクトリを参照していただくことで何をしているか わかるかと思います
  • 17. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 注意点と進め方
 17 ● 各ディレクトリで初回で動かす場合はディレクトリごとにnpm installが必要です 
 ● 00.init_templateが初期状態のディレクトリです 
 ○ こちらを拡張することでハンズオンを進めていきます 
 ● ソースを手打ちしていただいても良いですが、各ディレクトリのサンプルをコピペしていただいても問題ないです 
 ● ソース及び発表資料は公開いたしますので、途中でついていけなくなった方などは後日参照いただければと思い ます
 ● 割愛させて頂く部分が発生するかもしれませんが、その際も公開された資料をご確認ください 
 ● 今回は申し訳ありませんが、環境が動かない等のフォローはできない可能性があります。その際はソースの方を 追っていただければと思います 

  • 18. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 18 1. コンポーネントの基本(basic_of_component) 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて←ここまでは実施予定 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング

  • 19. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. basic_of_component:コンポーネントの基本
 19 ● Vue.jsはWebコンポーネントとVirtual DOMを軸にしたフレームワークです
 ○ Reactや、Angular(2以降)と似たフレームワークです
 ● *.vueという拡張子のファイルが画面の1パーツ(コンポーネント)となります。以下例です
 ○ Button.vue:ボタンのコンポーネント
 ○ Header.vue:ヘッダーのコンポーネント
 ○ App.vue:Button.vueとHeader.vueを組み合わせて画面を作るコンポーネント
  • 20. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue:ディレクトリ構成
 20 ❯ tree -L 2 . ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public ├── src │ ├── App.vue │ ├── assets │ ├── components │ ├── main.ts │ ├── router │ ├── shims-vue.d.ts │ ├── store │ └── views ├── tsconfig.json └── vite.config.ts コンポーネントのエントリポイント プログラムのエントリポイント ルーティングに関するファイル置き場 *.vueファイルをTypeScriptに認識させるための型定義 Vuexに関するファイル置き場 URLと紐づくコンポーネントの置き場 小分けされたコンポーネント置き場 画像などの静的なファイル置き場
  • 21. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. basic_of_component:コンポーネントの基本
 
 21 <template> <div id="app"> <div id="nav"> <!-- router/index.tsにかかれているルーティング情報から自動で aタグを作る --> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <!-- ルーティングされたコンポーネントがここに描画される--> <router-view /> </div> </template> <script lang="ts"> import { defineComponent } from "vue"; export default defineComponent({ name: "App", }); </script>
  • 22. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. basic_of_component:コンポーネントの基本
 
 22 App.vue
 router-link x 2
 router-view
 HelloWorld.vue

  • 23. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 23
  • 24. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 24 1. コンポーネントの基本 
 2. stateについて(state) 
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング

  • 25. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. state:stateについて
 ● setupメソッド
 ○ 各コンポーネントのエントリポイントとなるメソッド 
 ○ 呼ばれた段階ではまだレンダリングされていない状態 
 ● reactive関数
 ○ リアクティブなオブジェクトを作成できる 
 ○ リアクティブな状態が変化するとビューが自動的に更新される 
 ○ state.messageを更新すると、template側でstate.messageを使ってる部分も自動で変わる(後述) 
 25
  • 26. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. state:stateについて
 <template> <div id="app"> <div id="nav"> <!-- 追加 --> <p>{{ state.message }}</p> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <router-view /> </div> </template> 26 <script lang="ts"> import { defineComponent, reactive } from "vue"; interface State { message: string; } export default defineComponent({ name: "App", setup() { const state = reactive<State>({ message: "Hello Sample" }); return { state }; } }); </script>
  • 27. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. state:stateについて
 一番上に”Hello Sample”が追 加される
 27
  • 28. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 28 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて(event) 
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング

  • 29. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. event:イベントについて
 <template> <div id="app"> <div id="nav"> <p>{{state.message}}</p> <!-- 追加 --> <p> <button type="button" @click="onClick">メッセージを変更 </button> </p> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <router-view /> </div> </template 29
  • 30. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. event:イベントについて
 export default defineComponent({ name: "App", setup() { const state = reactive<State>({ message: "Hello Sample" }); // 追加 const onClick = () => { state.message = "clicked"; }; return { state, // 追加 onClick }; } }); 30
  • 31. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. event:イベントについて
 ● 関数の作り方
 ○ setup関数内で関数を作り、戻り値として返す 
 ○ template内で@clickなどで関数をイベントを紐付けする 
 ○ reactiveな値と共に別ファイルに書くこともできる(次ページ) 
 ● 表示の更新について 
 ○ reactiveで生成した変数を、関数内で更新すると自動でtemplate内の表示も変わる 
 ○ element.innerHTMLなどを利用した直接的なDOM書き換えは不要 31
  • 32. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. event:イベントについて
 import { AppState, useAppState } from './utils'; type State = AppState export default defineComponent({ name: "App", components: { Sample, Async }, setup() { const [state, onClick] = useAppState(); return { state, onClick }; } }); 32 reactiveな値と、値を変更する処理を別ファイルに書くこともでき る例(utils.ts)
 
 
 
 import { reactive } from "vue"; export interface AppState { message: string; } export const useAppState = (): [AppState, () => void] => { const state = reactive<AppState>({ message: "Hello Sample", }); const onClick = () => { state.message = "clicked"; }; return [state, onClick]; };
  • 33. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 33 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携(component_props) 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング

  • 34. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_props:コンポーネント間の連携 
 
 
 34 components/Sample.vueを作成
 <script lang="ts"> import { defineComponent } from "vue" interface State { localMessage: string; } export default defineComponent({ props: { parentMessage: { type: String, required: true, }, }, setup() { const state = reactive<State>({ localMessage: "child component" }); return { state }; }, }); </ script> <template> <div> <p>localMessage: {{ state.localMessage }}</p> <p>parentMessage: {{ parentMessage }}</p> </div> </template>
  • 35. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_props:コンポーネント間の連携
 <template> <div id="app"> <div id="nav"> <!-- 追加 --> <sample :parent-message="state.message" /> <!-- <p>{{ state.message }}</p> --> <!-- 以下略 --> </template> 35 <script lang="ts"> import { defineComponent, reactive } from "vue"; import Sample from './components/Sample.vue'; interface State { message: string; } export default defineComponent({ name: "App", // 追加 components: { Sample }, // 以下略 }); </script> App.vueを変更

  • 36. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_props:コンポーネント間の連携
 ● props
 ○ 親コンポーネントから渡ってくるデータ。変更不可 
 ■ 変更したい場合は変更用の処理を一緒に渡す(後述) 
 ○ プリミティブな値だけでなく、objectや関数も渡せる 
 ● 子コンポーネントの埋め込み方 
 ○ defineComponent内にcomponentsプロパティを追加 
 ○ template内でカスタムタグのように子コンポーネントを埋め込み 
 ● propsの渡し方について 
 ○ :`props名` で受け渡す 
 ■ v-bind:`prps名` のシンタックスシュガー 36
  • 37. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue:コンポーネント間の連携
 37 子コンポーネント(Sample.vue)内で親(App.vue)から渡された propsが表示される
 
 
 親での変更がpropsにも反映され、表示が変わる

  • 38. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 38 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更、component_events) 
 6. ライフサイクルについて 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング

  • 39. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_events:コンポーネント間の連携その2(propsの変更)
 
 39 Sample.vueを変更
 <template> <div> <p>localMessage: {{ state.localMessage }}</p> <p>parentMessage: {{ parentMessage }}</p> </div> <!-- 以下追加 --> <p> <button type="button" @click="updateMessage">propで更新</button> </p> <p> <button type="button" @click="emitClick">emitで更新</button> </p> </template>
  • 40. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_events:コンポーネント間の連携その2(propsの変更)
 
 40 Sample.vueを変更
 propsで変更用の関数を受け取る場合と、Eventで受け取る場合を追加
 <script lang="ts"> // 略 export default defineComponent({ props: { // 略 // 追加(propsで変更用の関数を受け取るケース ) updateMessage: { type: Function as PropType<() => void>, default: () => {}, }, }, emits: ["click"], setup(_, { emit }: SetupContext) { // 略 // 追加(Eventとして変更用の関数を受け取るケース ) const emitClick = () => { emit("click"); }; return { state, emitClick, // 追加 }; }, }); </script>
  • 41. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_events:コンポーネント間の連携その2(propsの変更)
 
 41 App.vueを変更
 propsとEventを渡すようにする
 <template> <div id="app"> <div id="nav"> <!-- 追加(propsと@click) --> <sample :parent-message="state.message" @click="onChildEmit" :update-message="onChildClick" /> <!-- 以下略 --> </template> <script lang="ts"> // 略 export default defineComponent({ // 略 setup() { // 略 // 追加(2つ) const onChildClick = () => { state.message = "child clicked"; }; const onChildEmit = () => { state.message = "child emit clicked"; }; return { state, onClick, // 追加(2つ) onChildClick, onChildEmit, }; }, }); </script>
  • 42. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_events:コンポーネント間の連携その2(propsの変更)
 
 42
  • 43. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. component_events:コンポーネント間の連携その2(propsの変更)
 
 ● propsとして関数受け渡し 
 ○ typeにFunctionを指定することでpropsとして関数を受け取れるようにする 
 ○ 関数の具体的な型はPropTypeを使うことで明示できる 
 ● Eventとしての関数受け渡し 
 ○ defineComponentのプロパティとしてemitsを追加(Vue3から) 
 ■ 呼び出す可能性のあるEvent一覧を文字列で追加 
 ■ objectで指定することで引数等のバリデーションも可能(今回は割愛) 
 ○ setup関数の第二引数、SetupContextのメンバーとしてemit関数がある 
 ○ emit(`呼びたいEvent名`, `引数`)で関数呼び出しできる 
 ■ 文字列で関数を呼び出すため具体的な型がつけにくい 43
  • 44. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 44 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて(lifecycle) 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング

  • 45. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. lifecycle:ライフサイクルについて ● ReactやAngularなどと同様にライフサイクルがあります 
 ○ https://v3.vuejs.org/guide/composition-api-lifecycle-hooks.html 
 ○ Vue2であったcreatedはsetupに統合されました 
 ● よく使うもの
 ○ mounted
 ■ DOMに触れられるようになったタイミングで発火 
 ○ unmounted
 ■ コンポーネントが破棄されるとき 
 ■ windowに何かしらイベント付けてるときの破棄などに使う(メモリリーク防止) 
 45
  • 46. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. lifecycle:ライフサイクルについて
 46 views/Home.vueを変更
 <script lang="ts"> // ライフサイクルのHookメソッドを追加 import { defineComponent, onMounted, onUnmounted } from "vue"; import HelloWorld from "../components/HelloWorld.vue"; export default defineComponent({ // 略 // setupメソッド追加 setup() { const resizeEvent = () => { console.log("resize window"); }; onMounted(() => { window.addEventListener("resize", resizeEvent); }); onUnmounted(() => { window.removeEventListener("resize", resizeEvent); }); }, }); </script>
  • 47. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 47 Aboutページに行くとリサイズイベントが止まる 

  • 48. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 48 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて 
 7. 非同期通信(ajax)
 8. computedとwatch
 9. ルーティング

  • 49. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajax) ● 生のXMLHttpRequestやfetch APIも使えますが、今回はライブラリを利用します 
 ○ https://github.com/axios/axios 
 ○ npm install axios @types/axios 
 ○ サンプルのリポジトリにはインストール済みです 
 ○ コンポーネントマウント前にデータ取得開始→state変更といった流れにします 
 49
  • 50. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajax) 
 50 ● 今回はBitCoinの金額を取得するAPIを利用します(coindesk api)
 ○ https://api.coindesk.com/v1/bpi/currentprice.json
 APIのレスポンスの型は次のものを想定
 interface Time { updated: string; updatedISO: string; updateduk: string; } interface Bpi { code: string; symbol: string; rate: string; description: string; rate_float: number; } interface CurrentPrice { time: Time; disclaimer: string; chartName: string; bpi: { USD: Bpi; GBP: Bpi; EUR: Bpi; }; }
  • 51. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajax) 
 51 components/Async.vueを作成
 <template> <pre v-if="state.apiData"> <code> {{ state.apiData }} </code> </pre> </template> <script lang="ts"> import { defineComponent, reactive } from "vue"; import axios from "axios"; // APIのinterfaceは略(前ページ参照) interface State { apiData: CurrentPrice | null; } export default defineComponent({ setup() { const state = reactive<State>({ apiData: null }); axios .get<CurrentPrice>("https://api.coindesk.com/v1/bpi/currentprice.json") .then((res) => { state.apiData = res.data; }); return { state, }; }, }); </script> <style scoped> pre { height: 300px; overflow: scroll; border: solid 1px #8a8a8a; } </style>
  • 52. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajax) 
 52 App.vueに追記
 <template> <div id="app"> <div id="nav"> <!-- 略 --> <async /> <!-- 略 → </div> <router-view /> </div> </template> <script lang="ts"> import { defineComponent, onMounted, onUnmounted, reactive } from "vue"; import Sample from "./components/Sample.vue"; // 追加 import Async from "./components/Async.vue"; interface State { message: string; } export default defineComponent({ name: "App", // Async追加 components: { Sample, Async }, // 略 }); </script>
  • 53. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue:非同期通信(Ajax) 
 53
  • 54. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajaxおまけ) 
 54 setup関数をasyncにしたい場合(Async.vue)
 export default defineComponent({ async setup() { const state = reactive<State>({ apiData: null }); const res = await axios.get<CurrentPrice>("https://api.coindesk.com/v1/bpi/currentprice.json"); state.apiData = res.data; return { state, }; }, });
  • 55. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajaxおまけ) 
 55 App.vueでAsyncコンポーネントをSuspenseで囲む
 <template> <!-- 略 --> <!-- 追加:Supenseで囲むことで非同期コンポーネントのフォールバックコンテンツを表示 --> <Suspense> <template #default> <async /> </template> <template #fallback> <div>loading...</div> </template> </Suspense> <!-- 略 --> </template>
  • 56. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. ajax:非同期通信(Ajax) ● async setupとする場合はSuspenseが必要 
 ○ https://v3.ja.vuejs.org/guide/migration/suspense.html 
 ● Suspense自体は非同期コンポーネントの描画を待つ間、代わりを表示する機能 
 ○ Suspenseなしasync setupなコンポーネントの部分は何も描画されなくなります 
 ● Vue2でのasync createdのつもりで使うと引っかかるかもしれないので注意 
 56
  • 57. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 57 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて 
 7. 非同期通信(Ajax)
 8. computedとwatch(computed_and_watch) 
 9. ルーティング

  • 58. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. computed_and_watch:computedとwatch 
 58 Sample.vueに追記
 <div> <!-- 以下2つに変更 --> <p>{{ localFullMessage }}</p> <p>{{ parentFullMessage }}</p> </div> <p> <button type="button" @click="updateMessage">propで更新</button> </p> <p> <button type="button" @click="emitClick">emitで更新</button> </p> </template>
  • 59. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. computed_and_watch:computedとwatch 
 59 // computedとwatchとwatchEffect追加 import { computed, watch, watchEffect, /* 略 */ } from "vue"; // 略 export default defineComponent({ // 略、propsをsetupの引数に追加 setup(props, { emit }: SetupContext) { const state = reactive<State>({ localMessage: "child component" }); // 以下色々追加 const localFullMessage = computed( () => `localMessage: ${state.localMessage}` ); const parentFullMessage = computed( () => `parentMessage: ${props.parentMessage}` ); watchEffect(() => { alert( `localMessageかparentMessageが変更されました。 ${localFullMessage.value} ${parentFullMessage.value}` ); }); watch( () => props.parentMessage, () => alert("parentMessageが変更されました。 ") ); const emitClick = () => { emit("click"); }; return { // 追加(localFullMessage、parentFullMessage) state, emitClick, localFullMessage, parentFullMessage, }; }, }); </script>
  • 60. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. computed_and_watch:computedとwatch
 ● watch、watchEffectを使うことでデータの監視が可能 
 ○ watchEffect:コールバックに指定した関数の中で使ってるリアクティブな変数が変更されたら関数 を再度実行する
 ○ watch:第一引数に指定した変数が変更されたら第2引数の関数を再度実行する 
 ● computedを使うことでデータに加工が可能 
 ○ 不変でreactiveなrefオブジェクトを返す関数 
 ○ computed内で使ってる変数が変更されると戻り値もリアクティブに変更される 
 60
  • 61. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. vue
 61 1. コンポーネントの基本 
 2. stateについて
 3. イベントについて
 4. コンポーネント間の連携 
 5. コンポーネント間の連携その2(propsの変更) 
 6. ライフサイクルについて 
 7. 非同期通信(Ajax)
 8. computedとwatch
 9. ルーティング(routing) 

  • 62. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. routing:ルーティング 
 
 
 62 <template> <div>Topページ</div> <Suspense> <template #default> <async /> </template> <template #fallback> <div>loading...</div> </template> </Suspense> </template> <script lang="ts"> import { defineComponent } from "vue"; import Async from "../components/Async.vue"; export default defineComponent({ components: { Async }, }); </script> URLとコンポーネントを紐付けるために、views/Top.vueを作成 
 中身では先程作成したAsync.vueを表示してみます 

  • 63. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. routing:ルーティング 
 
 
 63 // 略 const routes: RouteRecordRaw[] = [ { path: '/', component: Home }, { path: '/about', component: About }, // 追加 { path: '/top', component: Top }, ]; export const router = createRouter({ history: createWebHistory(), routes, }); <template> <div id="app"> <div id="nav"> <!-- 略 --> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> | <!-- 追加 --> <router-link to="/top">Top</router-link> </div> <router-view /> </div> </template> 続いて、router/index.tsとApp.vueを変更 
 (router/index.ts)
 (App.vue)

  • 64. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. 64
  • 65. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. routing:ルーティング 
 65 ● 各パスに1コンポーネントが紐づく形になります 
 ○ 指定したコンポーネントがApp.vueの<router-view />に入ります 
 ● コンポーネントを非同期ロードすることも可能 
 ○ ダイナミックインポートしたコンポーネントをパスに紐付ける 
 ○ 画面ロード時のファイルサイズを小さくすることができる 
 { path: '/top', component: () => import(/* webpackChunkName: "top" */ '../views/Top.vue') },
  • 66. Copyright  (C) 2021 Toranoana Inc. All Rights Reserved. まとめ
 66 ● Vue3と各機能について説明しました 
 ○ 単一コンポーネント内で完結するstateと更新処理について説明しました 
 ○ propsやeventを通したコンポーネント間の連携について説明しました 
 ○ Vue3は昨年リリースされたばかりの新しいフレームワークです 
 ○ Vue3での実際のアプリケーションの使い方について説明しました 
 ○ 説明してませんが、周辺ライブラリがVue3の記述に追いついてない場合があるので注意 
 ○ 公開するスライドには説明しなかった部分も含まれるのでぜひ見てみてください