【问题标题】:Ember computed property depending on service property not updatingEmber 计算属性取决于未更新的服务属性
【发布时间】:2017-04-10 10:58:43
【问题描述】:

在我的 Ember 2.8 应用程序中,我正在服务中建立 Websocket 连接。当用户登录时,连接 URL 会发生变化(然后将用户身份验证令牌作为查询参数包含在内)。

目前的用户服务很简单:

CurrentUserService = Ember.Service.extend(
  name: "current-user"

  user: null

  load: ->
    // Do some stuff
    @set("user", user)
 )

它完全按预期工作,我用它在页面上显示当前用户的用户名(除其他外)。

在 Websocket 服务中,我所做的只是根据 currentUser.user 创建一个计算属性,用于建立连接(取决于用户是否登录):

ActionCableService = Ember.Service.extend(
  name: "action-cable"

  cable: service()
  currentUser: service()

  testObs: Ember.observer("currentUser", ->
    console.log "currentUser changed, #{ @get("currentUser.user") }"
  )

  consumer: Ember.computed("currentUser.user", ->
     consumerUrl = "ws://localhost:10000/cable"

    if @get("currentUser").user?
      consumerUrl += "?token=#{ @get("currentUser.user.authToken") }"

    console.log(consumerUrl)
    return @get("cable").createConsumer(consumerUrl)
  ) 
)

问题是,消费者属性永远不会更新。它在页面加载时设置一次,当 currentUser 服务的用户属性更改时,consumer 不会更新,我的测试观察者也不会更新。

刷新页面时,有时会使用登录的consumerUrl,有时不会。
我猜有时会先恢复会话,有时会先发生动作电缆服务。

当动作有线电视服务首先加载时,我期望发生的事情是:

  1. Action cable 服务已加载,当前未设置用户,连接到公共 websocket
  2. 处理从会话数据中恢复用户的逻辑触发,设置currentUser.user(发生这种情况,我可以在我的页面上看到用户名)
  3. consumer 计算属性注意到 currentUser.user 更改并连接到私有 consumerUrl(不会发生)

我可以很容易地以一种不依赖于计算属性的方式解决这个问题,但我想知道这里出了什么问题。

【问题讨论】:

    标签: ember.js coffeescript


    【解决方案1】:

    Computed properties, by default, observe any changes made to the properties they depend on, and are dynamically updated when they're called.

    除非您调用或调用该计算属性,否则它不会执行您的预期代码。

    Observers,另一方面,当他们正在观察的属性发生变化时,无需调用即可做出反应。但是它们经常被过度使用,并且由于它们的同步特性很容易引入错误。

    您可以将观察者和计算属性重构为直接调用的辅助函数。这也使它们更容易进行单元测试。

    在您的控制器中,您可以处理登录的初始操作,如下所示:

    currentUser: Ember.inject.service(),
    
    actions: {
      login() {
        this.auth({ username: 'Mary' });
      },
    },
    
    auth(data) {
      // Send data to server for authentication...
    
      // ...upon response, handle the following within the promise's `then`
      // method, failures caught within `catch`, etc. But for purposes of 
      // demonstration, just mocking this for now...
      const response = { username: 'Mary', authToken: 'xyz', };
      this.get('currentUser').setConsumer(response);
    },
    

    当前用户服务然后可以设置它的属性,并在action-cable服务上调用一个辅助函数:

    actionCable: Ember.inject.service(),
    
    authToken: null,
    username: null,
    
    setConsumer(response) {
      this.set('authToken', response.authToken);
      this.set('username', response.username);
      this.get('actionCable').setConsumer();
    },
    

    action-cable 服务currentService 读取属性,设置consumerUrl,并调用cable 服务来创建消费者:

    cable: Ember.inject.service(),
    currentUser: Ember.inject.service(),
    
    setConsumer() {
      var consumerUrl = "ws://localhost:10000/cable";
    
      if (this.get("currentUser.username") !== null) {
        consumerUrl += "?token=" + (this.get("currentUser.authToken"));
      }
    
      console.log("ACTION CABLE SERVICE, Consumer URL: ", consumerUrl);
      this.get("cable").createConsumer(consumerUrl);
    }
    

    我创建了一个Ember Twiddle 来演示。

    【讨论】:

    • 谢谢!在我问这个问题之前,我已经实现了类似你的解决方案的东西,但是我错过了计算属性只有在被调用时才会被计算。
    【解决方案2】:

    另一种方法是在服务中发出event,然后在 init 方法中订阅事件并设置计算属性的依赖键的值以强制重新计算/更新它。

    【讨论】:

      猜你喜欢
      • 2014-03-01
      • 1970-01-01
      • 2012-08-04
      • 1970-01-01
      • 2014-01-07
      • 2014-08-19
      • 2013-03-19
      • 2019-04-18
      相关资源
      最近更新 更多