Ember:离开路由时自动销毁未提交的新模型实例
回答
首先明确:必须手动销毁未保存的实例,不然这些未提交的脏实例会一直留在Ember Data的Store里,可能干扰后续的数据查询、统计,甚至导致UI显示异常(比如列表里意外出现未保存的记录)。
针对你的场景,最佳的处理时机是路由的deactivate钩子——虽然实例存在控制器中,但路由可以直接访问控制器的模型属性,这个钩子会在用户离开当前路由时触发(不管是跳转、刷新还是关闭标签页,只要路由失活就会执行)。
给你一个简洁的Octane风格实现示例:
// app/routes/posts/new.js import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default class PostsNewRoute extends Route { @service store; model() { // 进入路由时创建新Post实例 return this.store.createRecord('post'); } deactivate() { const post = this.controller.model; // 只销毁未保存的脏实例 if (post?.hasDirtyAttributes) { // unloadRecord() 会从Store中移除实例且不发送后端请求 post.unloadRecord(); } } }
关键细节说明:
- 用
hasDirtyAttributes判断实例是否有未提交的修改,避免误删已经保存的记录(虽然新建场景下一般不会,但做判断更严谨)。 - 选择
unloadRecord()而不是destroyRecord():前者只是本地移除实例,不会向后端发送DELETE请求;后者会触发后端删除操作,这显然不是我们想要的(我们只是丢弃未保存的本地草稿)。 - 可选优化:如果用的是Ember 3.25+,可以用可选链操作符
post?.hasDirtyAttributes避免空值报错,更安全。
如果你的项目还在使用旧版Ember(非Octane),写法类似,只是装饰器换成传统的注入方式:
// 旧版Ember写法示例 import Route from '@ember/routing/route'; export default Route.extend({ store: Ember.inject.service(), model() { return this.get('store').createRecord('post'); }, deactivate() { let post = this.get('controller.model'); if (post && post.get('hasDirtyAttributes')) { post.unloadRecord(); } } });
内容的提问来源于stack exchange,提问作者Sean Mackesey




