Nuxt Composition APIの実行環境を作成する

Nuxtプロジェクトの作成

公式ドキュメントに従ってNuxt.jsをインストールしていく。
下記の前提条件は満たしているものとする。

前提条件

create-nuxt-app

プロジェクト名は仮に「nuxt-estat」とする。

1
$ npx create-nuxt-app nuxt-stat

インストール時の設定は次のとおり。
ここで、TypeScriptを選択することに注意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
create-nuxt-app v3.7.1
✨ Generating Nuxt.js project in nuxt-resas
? **Project name:** nuxt-resas
? **Programming language:** TypeScript
? **Package manager:** Yarn
? **UI framework:** Vuetify.js
? **Nuxt.js modules:** (Press **<space>** to select, **<a>** to toggle all, **<i>** to invert selection)
? **Linting tools:** (Press **<space>** to select, **<a>** to toggle all, **<i>** to invert selection)
? **Testing framework:** None
? **Rendering mode:** Universal (SSR / SSG)
? **Deployment target:** Static (Static/Jamstackhosting)
? **Development tools:** (Press **<space>** to select, **<a>** to toggle all, **<i>** to invertselection)
? **What is your GitHub username?** [ここにGitHubアカウント]
? **Version control system:** Git

Vue/composition-apiの導入

プロジェクトのディレクトリに移動し、@vue/composition-apiをインストール。

1
2
$ cd nuxt-resas
$ yarn add @vue/composition-api

plugins/composition-api.tsを作成。

composition-api.tslink
1
2
3
4
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';

Vue.use(VueCompositionApi);

nuxt.config.jsでプラグインを有効化。

nuxt.config.js#L36-L37link
36
37
plugins: [
{ src: '@/plugins/composition-api', ssr: true, },

Nuxt/composition-apiの導入

@nuxtjs/composition-apiをインストールする。

1
$ yarn add @nuxtjs/composition-api

nuxt.config.jsに@nuxtjs/composition-apiを追加する。

nuxt.config.js#L49-L53link
49
50
51
52
53
buildModules: [
'@nuxt/typescript-build',
'@nuxtjs/vuetify',
'@nuxtjs/composition-api/module',
],

Nuxt2とNuxt/composition APIの違い

composition APIを導入することで書き方がどう変わるのか。
こちらの記事で利用した、Highchartsでグラフを作成するコンポーネントで比較してみる。

Nuxt2の場合:

ColumnChart.vuelink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<template>
<div class="graph">
<highcharts :options="chartOptions" />
</div>
</template>

<script>
import { cloneDeep } from 'lodash'

export default {
props: {
displayData: {
type: Array,
required: true,
},
},
data() {
return {
colors: [
'#058DC7',
'#50B432',
'#ED561B',
'#DDDF00',
'#24CBE5',
'#64E572',
'#FF9655',
'#FFF263',
'#6AF9C4',
],
}
},
computed: {
series() {
const series = cloneDeep(this.displayData)
return series.reduce((acc, cur, i) => {
cur['color'] = this.colors[i]
acc.push(cur)
return acc
}, [])
},
chartOptions() {
return {
chart: {
height: 280,
zoomType: 'xy',
type: 'column',
},
title: {
text: null,
},
xAxis: {
min: 1990,
max: 2020,
scrollbar: {
enabled: true,
},
crosshair: true,
},
yAxis: {
opposite: false,
title: {
text: '',
},
},
plotOptions: {
series: {
pointWidth: 12,
animation: false,
label: {
connectorAllowed: false,
},
},
column: {
stacking: 'normal',
},
},
legend: {
enabled: false,
},
tooltip: {
pointFormat:
'<span style="color:{series.color}">{series.name}</span>: <b>{point.y}{point.unit}</b> ({point.percentage:.0f}%)<br/>',
shared: true,
},
credits: {
enabled: false,
},
series: this.series,
}
},
},
}
</script>

<style lang="sass" scoped>
.graph
margin-top: 10px
height: 100%
</style>

composition APIの場合:

ColumnChart.vuelink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<template>
<div class="graph">
<highcharts :options="chartOptions" />
</div>
</template>

<script lang="ts">
import { defineComponent, ref, computed } from '@nuxtjs/composition-api'
import { cloneDeep } from 'lodash'

type Series = {
name: string
data: {
x: number
y: number
unit: string
}
color: string
}

export default defineComponent({
props: {
displayData: {
type: Array,
required: true
}
},
setup(props) {
const colors = ref<string[]>([
'#058DC7',
'#7dbae5',
'#ff69b4',
'#DDDF00',
'#24CBE5',
'#64E572',
'#FF9655',
'#FFF263',
'#6AF9C4'
])

const colorList = computed((): string[] => {
const i = props.displayData.length
const c: string[] = cloneDeep(colors.value)
if (i === 1) {
return c.slice(0, 1)
} else {
return c.slice(1, c.length - 1)
}
})

const series = computed((): Series[] => {
const d: Series[] = props.displayData
const c = colorList.value

return d.reduce((acc, cur, i) => {
cur['color'] = c[i]
acc.push(cur)
return acc
}, [])
})

const chartOptions = computed(() => {
return {
chart: {
height: 280,
zoomType: 'xy',
type: 'column'
},
title: {
text: null
},
xAxis: {
min: 1990,
max: 2020,
scrollbar: {
enabled: true
},
crosshair: true
},
yAxis: {
opposite: true,
title: {
text: ''
}
// labels: {
// formatter() {
// return this.value.toLocaleString()
// }
// }
},
plotOptions: {
series: {
pointWidth: 12,
animation: false,
label: {
connectorAllowed: false
}
},
column: {
stacking: 'normal'
}
},
legend: {
enabled: false
},
tooltip: {
pointFormat:
'<span style="color:{series.color}">{series.name}</span>: <b>{point.y}{point.unit}</b> ({point.percentage:.0f}%)<br/>',
shared: true
},
credits: {
enabled: false
},
series: series.value
}
})
return {
chartOptions
}
}
})
</script>

<style lang="sass" scoped>
.graph
margin-top: 10px
height: 100%
</style>

defineComponent

v2.x のときは、Vue.extendが必要だったが、Composition API では、defineComponent に変更された。

1
2
3
4
5
<script lang="ts">
import { defineComponent } from '@vue/composition-api';

export default defineComponent({});
</script>

props → props

親コンポーネントから子コンポーネントへの渡し方は:users="data.users"のように渡す。親コンポーネントはComposition APIによる違いはない。

子コンポーネントでpropsの値を使って何らかの処理をするにはsetupの第1引数からpropsを取得して操作する。

setup関数

今まではdataプロパティやmethods、createdのようなライフサイクルフックなどそれぞれ分けて定義していたが、Composition APIではすべてsetup関数の中で定義する。

data → ref, reactive

dataはComposition APIでrefあるいはreactiveで表現される。
refはプリミティブな値を管理し、reactiveはオブジェクトや配列を管理する。
ただし、refにオブジェクトや配列を渡すと、内部でreactiveが呼ばれるため問題なく使える。

computed → computed

computed(算出プロパティ)はsetup関数のなかで呼び出す。
今まではthis.usersのようにthisを経由してもとになる値を参照していたが、 Composition APIではsetup関数内に定義された変数をそのまま参照する。