はじめに
仕事でChart.jsを使ってシステム作ってて、円チャートや棒チャートごとにそれぞれコンポーネントを作っていたため、共通処理が多く
Reactで良く見るHOCみたいなことをやればコード量を減らして綺麗になると思ったので、Vue.jsで出来るか調べてみた
結論
Vue.jsにはMixinという機能があり、HOCではないけど今回みたいな共通処理をどうにかしたい場合は、これで解決できそうだった
一応HOCでも実装してみてHOCの方が好みだったが、Vue.jsに関してはMixinを使うのが良い気がしたのでMixinを採用した
Mixinで実装
■ 修正前
BarChart.vue
export default Vue.extend({
computed: {
renderChart() {
// 各チャートの共通処理部分
// 主にチャートの表示制御(チャートをレンダリングしない場合はreturn)などをしている
if (!this.chart) return
if (!this.chart.length) {
...
return
}
...
// 各チャートの固有処理部分
const canvas = <HTMLCanvasElement>this.$el.querySelector('#bar-chart')
const ctx = <CanvasRenderingContext2D>canvas.getContext('2d')
...
}
}
})
※共通処理は他にもあるが、抜粋してます
■ 修正後
MixinChart.vue
export default Vue.extend({
data() {
return {
isShowChart: false
}
},
computed: {
isRenderChart() {
// 各チャートの共通処理部分をこのFunctionにまとめる
if (!this.chart) {
isShowChart = false
return
}
if (!this.chart.length) {
...
isShowChart = false
return
}
...
isShowChart = true
}
}
})
BarChart.vue
import CommonChart from '@/components/mixins/CommonChart/CommonChart.vue'
export default Vue.extend({
data() {
return {
isShowChart: false
}
},
computed: {
renderChart() {
if (!this.isShowChart) return
// 各チャートの固有処理部分
const canvas = <HTMLCanvasElement>this.$el.querySelector('#bar-chart')
const ctx = <CanvasRenderingContext2D>canvas.getContext('2d')
...
}
},
mixins: [CommonChart]
})
HOCで実装
https://github.com/vuejs/vue/issues/6201
こちらを参考にしながら実装
hocという関数でBarChartをラップしている。簡単な処理の流れは以下
①isRenderChartでチャートの共通処理を行い、isShowChartを判断
②props経由でisShowChartをBarChartに渡す
③BarChartでisShowChartを見てチャートのレンダリングの有無を判断
Parent.vue
import BarChart from '@/components/BarChart/BarChart.vue'
const hoc = (w: any) =>
Vue.extend({
props: w.options.props,
data: w.options.data,
computed: {
isRenderChart() {
// 各チャートの共通処理部分をこのFunctionにまとめる
if (!this.chart) {
return false
}
if (!this.chart.length) {
...
return false
}
...
return true
}
},
render(h) {
return h(w, {
props: { ...this.$props, ...{ isShowChart: this.isRenderChart } }
})
}
})
export default Vue.extend({
components: {
BarChart: hoc(BarChart)
}
})
BarChart.vue
export default Vue.extend({
props: ['isShowChart'],
computed: {
renderChart() {
if (!this.isShowChart) return
// 各チャートの固有処理部分
const canvas = <HTMLCanvasElement>this.$el.querySelector('#bar-chart')
const ctx = <CanvasRenderingContext2D>canvas.getContext('2d')
...
}
}
})