vue.jsのスタイルガイドはとても充実しています。
vue.jsに慣れてきたら、一度は読んでおきたいところですが、とても長いですね。
今回はスタイルガイドを踏まえた上で注意しておきたいポイントをまとめておきます。
作成時と更新時に同じ処理をする場合
以下のように、作成時に何かしらのデータを取得して、更新時にも同じ処理を走らせる場合。例えば、検索フォームで最初は一覧を表示して、入力された文字列によってフィルターをかける場合などがあります。
searchTextが更新されたら、hogehoge()が発火します。
created () {
this.hogehoge()
}
watch: {
searchText() {
this.hogehoge()
}
}
それがこうなります。
⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎⬇︎
watch: {
searchText: {
handler: 'hogehoge',
immediate: true
}
}
そしておそらく検索フォームなどはコストの高い処理になるのでlodash関数の_.debounceを使って、負荷を軽減させてあげると良いと思います。
watch: {
searchText: {
handler: 'hogehoge',
immediate: true
}
},
methods: {
hogehoge: _.debounce(function(searchText) {
//APIでデータを持ってきたり、フィルター処理など
}
}
immediate: true
オプションを付与することで、作成時にもhandlerに指定した関数が実行されるようになります。ちなみにimmediateの発火タイミングはbeforeCreate
とcreated
の間です。
こちらに調べてくれた方がいました!有難や🙏
親から子へデータを渡す
長くなってしまったので別の記事へ。【サンプル付】Vue.jsでComponentを作成する! 正しくpropsを使おう!
親コンポーネントインスタンスへのアクセス
vue.jsで$parent
を使用するのは、処理を煩雑にする上、子から親のデータを変更するのはデータの変更の処理を追いづらくなるので、あまりいいものではありません。そこで$parentの代替となるのが、provide/injectです。
こちらは2.2.0 から新しく実装されました。
こちらに素晴らしいサンプルがあります。以下はサンプルのコード
<!DOCTYPE html>
<html>
<head>
<title>Dependency Injection Google Maps Demo</title>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAHbknPTCvUSgWwU0jJ68m4h6b7vpyP6hM"></script>
<script src="https://unpkg.com/vue"></script>
<style>
.map {
width: 100%;
height: 400px;
}
</style>
</head>
<body>
<div id="app">
<google-map>
<google-map-marker v-bind:places="vueConfCities"></google-map-marker>
</google-map>
</div>
<script>
Vue.component("google-map", {
provide: function() {
return {
getMap: this.getMap
};
},
data: function() {
return {
map: null
};
},
mounted: function() {
this.map = new google.maps.Map(this.$el, {
center: { lat: 0, lng: 0 },
zoom: 1
});
},
methods: {
getMap: function(found) {
var vm = this;
function checkForMap() {
if (vm.map) {
found(vm.map);
} else {
setTimeout(checkForMap, 50);
}
}
checkForMap();
}
},
template: '<div class="map"><slot></slot></div>'
});
Vue.component("google-map-marker", {
inject: ["getMap"],
props: ["places"],
created: function() {
var vm = this;
vm.getMap(function(map) {
vm.places.forEach(function(place) {
new google.maps.Marker({
position: place.position,
map: map
});
});
});
},
render(h) {
return null;
}
});
new Vue({
el: "#app",
data: {
vueConfCities: [
{
name: "Wrocław",
position: {
lat: 51.107885,
lng: 17.038538
}
},
{
name: "New Orleans",
position: {
lat: 29.951066,
lng: -90.071532
}
}
]
}
});
</script>
</body>
</html>
このサンプルでは、親コンポーネントのgoogle-map
がgetMap
をprovide(提供)して、子コンポーネントのgoogle-map-marker
で、getMap
をinject(依存注入)して、取り込んでいます。これにより<google-map>
インスタンス全体にアクセスせず、どの子孫コンポーネントからでもgetMap
だけにアクセスできます。素晴らしい!!
無駄な変更や削除がなくなりコンポーネントの安全性も高まりますし、
もし特定のプロパティをシェアしたいのなら、Vuexなどを使用する方が良いのかもしれません。
コンポーネントの命名規則
スタイルガイドで強く推奨されている部分で、以下のセクションを一通り読んでおきましょう。
上のセクションの基底コンポーネントの名前に、以下のような文言があります。
これらのコンポーネントはとても頻繁に使われるので、あらゆる場所で import するよりも単純にグローバルにしてしまいたいと思うかもしれません。プレフィックスによって、それを Webpack でできるようになります。
コンポーネントに正しい命名をすることで、以下のようにグローバルにimportすることができるメリットを得られます。さらにコンポーネントを探す手間や、可読性も上がるので必ず上記のセクションを読んでおきましょう。
var requireComponent = require.context("./src", true, /Base[A-Z]\w+\.(vue|js)$/)
requireComponent.keys().forEach(function (fileName) {
var baseComponentConfig = requireComponent(fileName)
baseComponentConfig = baseComponentConfig.default || baseComponentConfig
var baseComponentName = baseComponentConfig.name || (
fileName
.replace(/^.+\//, '')
.replace(/\.\w+$/, '')
)
Vue.component(baseComponentName, baseComponentConfig)
})
参考
- 「Vueコンサルが教えたくない7つの真実」を勉強してみた
- 監視プロパティを用いた非同期処理
- $watchでオブジェクトの変更を監視する方法
- vue.js スタイルガイド
- How to correctly use Vue JS watch with lodash debounce
まとめ
これはいいなと思ったものがあり次第更新していきます!