You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动