貼文討論:[作業問題] JavaScript系列八:第5課



OK 花了不少時間,我終於研究完了

主要問題出在這裡

  data() {
    return {
      weightChart: null,
      // ...others
    }
  },

放在 data 這邊的,會被引進 vue 的 reactivity 機制

但是,我們並不希望 weightChart 被 vue 監聽、自動更新

我們希望透過 this.weightChart.update() 手動更新,也就是我們自己管理相關 state,然後手動去觸發更新

這種情況,把 weightChart 移到 data 外面即可,就變成普通的物件屬性,不會具有 reactivity

  weightChart: null,
  data() {
    return {
      // ...others
    }
  },

執行之後會發現,「新增」沒問題了,但是「刪除」依然有問題

繼續觀察程式碼,可能有關的是這裡

  this.weightChart = new Chart(this.$refs.weightChartDOM, {
    type: 'line',
    data: {
      labels: this.dates,
      datasets: [{
        label: '體重',
        data: this.weights,
        borderWidth: 1
      }]
    },
  });

labels 與 datasets 期待的是陣列資料

使用 console.log(this.dates) 觀察變數型別,會發現我們傳進去的是帶有 vue reactivity 功能的 data(vue 使用 proxy 實作)

Chart.js 內部可能也有在監聽 變數 變化的機制,所以衝突

來試著把這邊的 reactivity 也拿掉。方法有很多種,我這邊用最土炮的一種:轉成 JSON 字串再轉回來

  this.weightChart = new Chart(this.$refs.weightChartDOM, {
    type: 'line',
    data: {
      labels: JSON.parse(JSON.stringify(this.dates)),
      datasets: [{
        label: '體重',
        data: JSON.parse(JSON.stringify(this.weights)),
        borderWidth: 1
      }]
    },
  });

除此之外,在新增、刪除的最後

  this.weightChart.data.labels = this.dates
  this.weightChart.data.datasets[0].data = this.weights
  this.weightChart.update()

也一併改掉,讓事情單純一點:我們都按照 Chart.js 期待的資料型態去傳

  this.weightChart.data.labels = JSON.parse(JSON.stringify(this.dates))
  this.weightChart.data.datasets[0].data = JSON.parse(JSON.stringify(this.weights))
  this.weightChart.update()

大功告成!解決問題!


備註一

就跟其他眾多解法一樣:以上這做法,也只算是 workaround

因為我們沒有興趣深入研究 Chart.js 監聽 labels 跟 datasets 的變化機制

(通常只有 senior developers 會在這時候想深入進去搞懂)

既然都是 workaround,就隨便找個方法搞定就是了,解法不一定很有道理(我們根本沒有100%搞懂)

備註二

proxy 型別,一般來說,會跟普通的資料型別相容

也就是說,通常把 vue reactivity 狀態,直接傳給第三方套件,根本沒問題!

不需要這樣 JSON 轉來轉去的!這是一個剛好 vue 跟第三方套件衝突的特例!

備註三

實務上,這種高互動的 UI library,都會自己出一套框架版本的,先處理掉地雷

實務上以使用框架版本為主,所以不會太常碰到這種需要 workaround 的情況(但偶爾還是會遇到)

本課的原意是故意不用框架版本,練習看看手動整合,沒想到真的踩到地雷

(但是也好,也是一種練習)

備註四

在前端框架領域,整合框架 狀態html 元件第三方外部元件 時,有兩種哲學

第一種哲學就是通通由框架處理好,這種元件稱之為 controlled components。開發元件時比較吃力,但使用元件時比較輕鬆

第二種哲學就是,自己手動管理外部元件的狀態,這種元件稱之為 uncontrolled components。開發元件時比較輕鬆,但使用元件時比較吃力

可以 google 搜尋 controlled components vs uncontrolled components,看不懂沒關係,有更多使用套件的經驗之後,會開始看懂我在講什麼


👉 身份:資深全端工程師、指導過無數人半路出家轉職 👉 使命:打造 CodeLove 成為優質新手村,讓非本科也有地方自學&討論