Vue.jsは、使いやすさと柔軟性を兼ね備えたJavaScriptフレームワークです。
本記事では、Vue.jsの基本概念と実践的な使い方を、具体的なコード例を交えながら解説します。
Vue.jsを初めて学ぶ方にも理解しやすい内容となっていますので、ぜひ最後までご覧ください。
目次
コンポーネントとは
分かりやすく言うと、コンポーネントは「ウェブページの特定の部分」を担当する小さな部品のようなものです。
特定の部分とは1つのページのことであったり、セレクトボックスだったり、ラジオボタンだったりのことを表しています。
このコンポーネントへの理解が重要なポイントになるので、他よりも厚めに説明しておきます。
コンポーネントの例
以下に、シンプルなVue.jsコンポーネントの例を示します。
親コンポーネント
親コンポーネントは、子コンポーネントを使用してデータを渡す役割を持ちます。
<!-- ParentComponent.vue -->
<template>
<div>
<h1>親コンポーネント</h1>
<ChildComponent :message="parentMessage"/>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentMessage: 'Hello from Parent Component!'
};
}
};
</script>
<style scoped>
h1 {
color: blue;
}
</style>
子コンポーネント
子コンポーネントは、親コンポーネントから渡されたデータを受け取りそれを表示します。
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子コンポーネント</h2>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
}
};
</script>
<style scoped>
h2 {
color: green;
}
</style>
コンポーネントの説明
- template: コンポーネントのHTML構造を定義します。ここでは、親コンポーネント内に子コンポーネントが含まれています。
- script: コンポーネントのロジックを定義します。データ、プロパティ、メソッド、ライフサイクルフックなどが含まれます。
- style: コンポーネントの見た目を定義します。
scoped
キーワードを使用することで、スタイルがそのコンポーネントに限定されます。
例の説明
親コンポーネント(ParentComponent.vue)
template
セクションでは、<ChildComponent>
タグを使用して子コンポーネントを組み込み、message
プロパティにparentMessage
の値を渡しています。
data
(※)オプションでparentMessage
というデータプロパティを定義しています。components
オプションで、ChildComponent
をインポートし、登録しています。
子コンポーネント(ChildComponent.vue)
template
セクションでは、親コンポーネントから受け取ったmessage
プロパティを表示しています。
props
(※)オプションで、親コンポーネントから受け取るmessage
プロパティを定義しています。type
はString
であり、必須であることを指定しています。
※ data
やprops
については後で説明が出てきます。
このようにコンポーネントを使うことでアプリケーションのUIを小さな再利用可能な部分に分割し、各部分を独立して管理および開発することができます。
コンポーネントは、複雑なアプリケーションをシンプルで直感的なものにし開発プロセスを効率化します。
propsとは
props
は、親コンポーネントから子コンポーネントにデータを渡すための機能です。
親コンポーネントから渡されたデータは、子コンポーネント内で読み取り専用(readonly)となります。
コード例
<!-- 親コンポーネント -->
<template>
<ChildComponent message="Hello from Parent!"/>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<!-- 子コンポーネント -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
}
};
</script>
dataとは
data
オプションは、コンポーネントのインスタンスに対して持つ状態(ステート)を定義します。
data
オプションは関数として定義され、その関数がオブジェクトを返します。
コード例
<template>
<div>{{ count }}</div>
<button @click="incrementCount">Increment</button>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
incrementCount() {
this.count++;
}
}
};
</script>
asyncDataとは
asyncData
はNuxt.js特有のメソッドで、コンポーネントがレンダリングされる前にデータを取得し、それをコンポーネントのデータとして設定します。
コード例
export default {
async asyncData({ params }) {
const data = await fetch(`https://api.example.com/data/${params.id}`)
.then(res => res.json());
return { data };
}
};
computedとは
computed
プロパティは依存関係に基づいて動的に計算されたプロパティを定義します。
これによりデータの変化に応じて自動的に再計算されます。
コード例
<template>
<div>{{ reversedMessage }}</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, World!'
};
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('');
}
}
};
</script>
stateとは
Vue.js自体にはstate
という特定の概念はありませんが、Vuexを使用して状態管理を行う際にstate
という名前のオプションがよく使われます。
state
はアプリケーションの中央で管理される状態を保持します。
コード例
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
}
});
<!-- コンポーネント内での使用 -->
<template>
<div>{{ count }}</div>
<button @click="incrementCount">Increment</button>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
computed: {
...mapState(['count'])
},
methods: {
...mapMutations(['increment'])
}
};
</script>
data-cyとは
data-cy
はテスト対象要素を指定するために使われるカスタム属性です。
Cypressのようなエンドツーエンドテストツールで、特定の要素を簡単に識別するために使用されます。
コード例
<template>
<button data-cy="increment-button">Increment</button>
</template>
// Cypressテスト例
describe('Increment Button', () => {
it('increments the count', () => {
cy.visit('/');
cy.get('[data-cy=increment-button]').click();
cy.contains('1');
});
});
watchとは
watch
は特定のデータプロパティの変更を監視し、変更があった場合に指定した処理を実行するために使用されます。
変更前と変更後の値を引数として受け取ることができます。
コード例
<template>
<div>{{ count }}</div>
<button @click="incrementCount">Increment</button>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
incrementCount() {
this.count++;
}
},
watch: {
count(newVal, oldVal) {
console.log(`カウントが ${oldVal} から ${newVal} に変更されました。`);
}
}
};
</script>
mountedとは
mounted
フックはコンポーネントがDOMにマウントされた後に実行されます。
これによりDOM要素へのアクセスや初期化処理を行うことができます。
コード例
<template>
<div ref="myElement">This is a mounted element</div>
</template>
<script>
export default {
mounted() {
console.log(this.$refs.myElement);
}
};
</script>
mixinsとは
mixins
は複数のコンポーネント間で再利用可能なコードを定義するための仕組みです。
mixins
内のデータ、メソッド、ライフサイクルフックは、コンポーネントに「ミックスイン」されます。
コード例
// mixin.js
export const myMixin = {
data() {
return {
mixinData: 'This is mixin data'
};
},
methods: {
mixinMethod() {
console.log('This is a mixin method');
}
}
};
<!-- コンポーネント内での使用 -->
<template>
<div>{{ mixinData }}</div>
</template>
<script>
import { myMixin } from './mixin';
export default {
mixins: [myMixin]
};
</script>
fetchとは
fetch
はAPIからデータを取得するためのメソッドです。
Nuxt.jsでよく使われ、サーバーサイドレンダリング(SSR)や静的サイト生成時にデータを取得できます。
コード例
export default {
async fetch({ store }) {
const data = await fetch('https://api.example.com/data')
.then(res => res.json());
store.commit('setData', data);
}
};
middlewareとは
middleware
はルートに対してアクセスする前に実行される関数です。
認証やリダイレクトなどの処理を行うために使用されます。Nuxt.jsでよく使われます。
コード例
// middleware/auth.js
export default function ({ store, redirect }) {
if (!store.state.authenticated) {
return redirect('/login');
}
}
// nuxt.config.js
export default {
router: {
middleware: 'auth'
}
};
画面遷移時のデータ取得のフロー
コード例
// pages/index.vue
<template>
<div>{{ data }}</div>
</template>
<script>
export default {
asyncData({ params }) {
return fetch(`https://api.example.com/data/${params.id}`)
.then(res => res.json())
.then(data => {
return { data };
});
}
};
</script>
親から子、孫コンポーネントに値を渡す方法
コード例
<!-- 親コンポーネント -->
<template>
<ChildComponent :parent-value="parentValue"/>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentValue: 'Value from Parent'
};
}
};
</script>
<!-- 子コンポーネント -->
<template>
<div>
<GrandchildComponent :child-value="parentValue"/>
</div>
</template>
<script>
import GrandchildComponent from './GrandchildComponent.vue';
export default {
components: {
GrandchildComponent
},
props: {
parentValue: {
type: String,
required: true
}
}
};
</script>
<!-- 孫コンポーネント -->
<template>
<div>{{ childValue }}</div>
</template>
<script>
export default {
props: {
childValue: {
type: String,
required: true
}
}
};
</script>
親から子、孫コンポーネントに値を渡す方法:provideとinjectを使うパターン
provide
とinject
は、Vue.jsで深いコンポーネント階層にデータを渡すための便利な機能です。
この方法を使うと、複数階層をまたいでデータを受け渡すことができます。
ここでは具体的なコード例を用いて説明します。
- 親コンポーネント:
provide
を使ってデータ(parentValue
)を提供します。 - 子コンポーネント:
inject
を使って親コンポーネントから提供されたデータ(sharedValue
)を受け取ります。 - 孫コンポーネント:
inject
を使って子コンポーネントからデータ(sharedValue
)を受け取ります。
親コンポーネント
親コンポーネントでは、provide
オプションを使ってデータを提供します。
<!-- ParentComponent.vue -->
<template>
<div>
<p>親コンポーネント: {{ parentValue }}</p>
<ChildComponent />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentValue: 'Value from Parent'
};
},
provide() {
return {
sharedValue: this.parentValue
};
}
};
</script>
子コンポーネント
子コンポーネントではinject
オプションを使ってデータを受け取ります。
このデータはさらに孫コンポーネントに渡すことも可能です。
<!-- ChildComponent.vue -->
<template>
<div>
<p>子コンポーネント: {{ sharedValue }}</p>
<GrandchildComponent />
</div>
</template>
<script>
import GrandchildComponent from './GrandchildComponent.vue';
export default {
components: {
GrandchildComponent
},
inject: ['sharedValue']
};
</script>
孫コンポーネント
孫コンポーネントでも同様にinject
オプションを使ってデータを受け取ります。
<!-- GrandchildComponent.vue -->
<template>
<div>
<p>孫コンポーネント: {{ sharedValue }}</p>
</div>
</template>
<script>
export default {
inject: ['sharedValue']
};
</script>
最後に
この記事ではVue.jsの基本概念から実践的な使用例までを詳しく解説しました。
各機能の説明と具体的なコード例を通じて、Vue.jsを効果的に学び、プロジェクトに活用できるようになっていただければ幸いです。
フリーランスやフルリモート環境に興味がある方は、下記の記事をご参考ください。