LoginSignup
6
6

More than 5 years have passed since last update.

Vue.jsでHOC的なことをやりたい

Posted at

はじめに

仕事で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')
      ...
    }
  }
})
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6