Svelte中含setter的ES6类更新属性后视图不响应问题
问题原因
Svelte的响应式是编译时静态分析实现的,普通ES6类实例的内部属性修改不会被自动追踪:你在类方法里修改currentName时,Svelte没有收到任何状态变更通知,自然不会触发视图重渲染,所以会出现控制台值正确、页面不更新的情况。
正确实现方式
你之前判断的用writable store是正确方向,核心是把需要响应式的状态交给Svelte的store管理,类方法修改状态时触发store的更新通知,组件侧自动订阅状态变化即可。
第一步:修改router.js
把需要响应式的状态封装为store,类内部保留可写权限,对外暴露只读的响应式状态,避免外部随意篡改内部状态:
import { writable, derived, get } from 'svelte/store'; export class Router { constructor(pageMap) { this.pageMap = pageMap; // 私有可写store,仅类内部方法可修改 const _activePage = writable({}); // 对外暴露只读响应式状态 this.current = derived(_activePage, page => page); this.currentName = derived(_activePage, page => page.name ?? ''); this._activePage = _activePage; } get name() { return get(this._activePage).name; } set name(pageName) { const targetPage = this.pageMap[pageName]; if (!targetPage) return; // 更新store,自动通知所有订阅者 this._activePage.set(targetPage); } navigate(target) { this.name = target; console.log(get(this._activePage).name); } }
第二步:修改App.svelte组件
注意Svelte单文件组件的后缀为.svelte,模板中使用$前缀自动订阅store值,值变更时会自动触发视图更新:
<script> import { Router } from './router.js'; const pageMap = { start: { title: 'start', name: 'world!', }, end: { title: 'end', name: '-- it works!!!', }, } const page = new Router(pageMap); page.name = 'start'; </script> <h1>Hello {$page.currentName}</h1> <button on:click={() => page.navigate('end')}> change to "it works" </button> <button on:click={() => page.navigate('start')}> change back to "world!" </button>
补充说明
- Svelte不会自动追踪普通对象、类实例的深层属性变更,所有跨组件/跨作用域的共享响应式状态,优先使用内置store实现,稳定性更高,还自带自动取消订阅的内存管理能力,不需要手动处理清理逻辑。
- 如果你不想依赖内置store,也可以自己在类中实现订阅发布模式:内部维护订阅回调列表,属性变更时遍历执行回调,组件挂载时订阅状态变更、把值同步给组件内的顶层响应式变量即可,但这种自定义实现需要手动处理组件卸载时的取消订阅逻辑,容易出现内存泄漏,不推荐新手使用。
内容的提问来源于stack exchange,提问作者Eric Knechtges
相关产品推荐
相关产品推荐

