AlpineJS 3 搭配 Charts.js 4.4.6 调用Chart.update()触发栈溢出错误
解决AlpineJS与Chart.js v3+更新时栈溢出问题
问题原因
Chart.js v3及以上版本会对传入的数据对象进行深度响应式监听,而AlpineJS自身也有一套响应式系统。当直接将Alpine的响应式data对象传给Chart.js实例时,两者的监听机制会互相触发更新,形成无限递归,最终导致Maximum call stack size exceeded错误。而Chart.js 2.9.4及更早版本没有这种深度监听逻辑,所以不会出现冲突。
解决方案
核心思路是切断AlpineJS与Chart.js的响应式数据绑定,不让两者共享同一个数据对象:
1. 初始化Chart时传入数据副本
在init方法中,不要直接传递this.data,而是创建数据副本,避免Chart.js监听Alpine的响应式对象。
2. 更新数据时直接操作Chart实例的数据
更新时直接修改Chart实例的data属性,再调用update(),无需通过Alpine的响应式数据中转,避免触发不必要的响应式更新。
修改后的完整代码:
<div x-data="chartComponent()" class="max-w-xl mx-auto"> <canvas id="myChart"></canvas> <button @click="updateChart" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" > Update Chart </button> </div> <script> function chartComponent() { return { chart: null, // Alpine本地存储数据,仅用于初始值备份 localData: { labels: ['January', 'February', 'March', 'April', 'May'], datasets: [{ label: 'Sales', data: [10, 20, 30, 40, 50], backgroundColor: 'rgba(75, 192, 192, 0.2)', borderColor: 'rgba(75, 192, 192, 1)', borderWidth: 1 }] }, init() { const ctx = document.getElementById('myChart').getContext('2d'); // 创建数据副本传给Chart.js,切断与Alpine响应式绑定 const chartData = JSON.parse(JSON.stringify(this.localData)); this.chart = new Chart(ctx, { type: 'bar', data: chartData, options: { responsive: true, plugins: { legend: { position: 'top', }, tooltip: { callbacks: { label: function (context) { return `${context.label}: ${context.raw}`; } } } } } }); }, updateChart() { // 直接修改Chart实例的数据 this.chart.data.datasets[0].data = [50, 40, 30, 20, 10]; // 同步更新Alpine本地数据(按需选择) this.localData.datasets[0].data = [50, 40, 30, 20, 10]; this.chart.update(); } }; } </script>
补充说明
- 如果不需要在Alpine中保留数据副本,可以直接在
init里定义独立的Chart数据,完全脱离Alpine的响应式系统。 JSON.parse(JSON.stringify())是通用的深拷贝方式,适用于各种数据结构;如果数据结构简单,使用对象/数组展开语法做浅拷贝也能满足需求。
内容的提问来源于stack exchange,提问作者zhovtyj
相关产品推荐
相关产品推荐

