OK 花了不少時間,我終於研究完了
主要問題出在這裡
data() { return { weightChart: null, // ...others } },
放在 data 這邊的,會被引進 vue 的 reactivity 機制
但是,我們並不希望 weightChart 被 vue 監聽、自動更新
我們希望透過 this.weightChart.update() 手動更新,也就是我們自己管理相關 state,然後手動去觸發更新
this.weightChart.update()
這種情況,把 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 實作)
console.log(this.dates)
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 元件、第三方外部元件 時,有兩種哲學
狀態
html 元件
第三方外部元件
第一種哲學就是通通由框架處理好,這種元件稱之為 controlled components。開發元件時比較吃力,但使用元件時比較輕鬆
controlled components
第二種哲學就是,自己手動管理外部元件的狀態,這種元件稱之為 uncontrolled components。開發元件時比較輕鬆,但使用元件時比較吃力
uncontrolled components
可以 google 搜尋 controlled components vs uncontrolled components,看不懂沒關係,有更多使用套件的經驗之後,會開始看懂我在講什麼
controlled components vs uncontrolled components
精選技術文章、免費程式設計資源、以及業界重要新聞!
OK 花了不少時間,我終於研究完了
主要問題出在這裡
放在 data 這邊的,會被引進 vue 的 reactivity 機制
但是,我們並不希望 weightChart 被 vue 監聽、自動更新
我們希望透過
this.weightChart.update()
手動更新,也就是我們自己管理相關 state,然後手動去觸發更新這種情況,把 weightChart 移到 data 外面即可,就變成普通的物件屬性,不會具有 reactivity
執行之後會發現,「新增」沒問題了,但是「刪除」依然有問題
繼續觀察程式碼,可能有關的是這裡
labels 與 datasets 期待的是陣列資料
使用
console.log(this.dates)
觀察變數型別,會發現我們傳進去的是帶有 vue reactivity 功能的 data(vue 使用 proxy 實作)Chart.js 內部可能也有在監聽
變數
變化的機制,所以衝突來試著把這邊的 reactivity 也拿掉。方法有很多種,我這邊用最土炮的一種:轉成 JSON 字串再轉回來
除此之外,在新增、刪除的最後
也一併改掉,讓事情單純一點:我們都按照 Chart.js 期待的資料型態去傳
大功告成!解決問題!
備註一
就跟其他眾多解法一樣:以上這做法,也只算是 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
,看不懂沒關係,有更多使用套件的經驗之後,會開始看懂我在講什麼