0

我在ember.js應用程序創建的頂部導航欄中,並將其轉換成一個組件,這樣我可以有一個簡單的「歡迎didReceiveAttrs()的一個組件{{} currentUser.fullName }「一旦用戶登錄,就會進行介紹。導航欄將成爲組件的原因還有一些,但現在這正是我想要正確工作的原因。我們也使用ember-simple-auth插件,並且使用session.isAuthenticated值來實現此目的。Ember.js計算屬性VS觀察員VS

當然,我有一個「登錄」的路線,當在用戶登錄,他們正在過渡到「索引」。出於某種原因,在過渡到'索引'期間,似乎並沒有立即發現session.isAuthenticated值。我不知道這是爲什麼,但那是另一個問題。

無論如何,我用了很多組件在本申請和大多數這些組件從會議獲得他們的價值觀和獨立路線的查詢商店,讓我可以在多個線路使用這些組件。導航欄也不例外。現在,我有以下工作代碼:

export default Ember.Component.extend({ 
    layout, 
    session: Ember.inject.service(), 
    currentUser: Ember.inject.service(), 
    isAuthenticated: Ember.observer('session.isAuthenticated', function() { 
     this.didReceiveAttrs(); 
    }), 
    currentUserFullName: null, 
    user: null, 
    tagName: 'navbar-main', 
    className: ['navbar', 'main'], 
    didReceiveAttrs() { 
     this._super(...arguments); 

     if (this.get('session.isAuthenticated')) { 
      this._setCurrentUser(); 
     } 
    }, 
    _setCurrentUser() { 
     this.get('currentUser').load().then(user => this.set('user', user)); 
    }, 
    onGetCurrentUser: Ember.observer('user', function() { 
     this.getUser(); 
    }), 
    getUser: function() { 
     var user = this.get('user'); 

     if(user) { 
      this.set('user', user); 
      this.set('currentUserFullName', user.get('fullName')); 
     } else { 
      user = this.get('store').findRecord('user', 'me'); 
      this.set('user', user); 
      this.set('currentUserFullName', user.get('fullName')); 
     } 
    } 
}); 

一切我讀建議只使用didReceiveAttrs(),而不是觀察員。此外,它說計算出來的屬性通常是你想要對觀察者使用的。不過,我似乎無法得到任何無勞動如下:

isAuthenticated: Ember.observer('session.isAuthenticated', function() { 
    this.didReceiveAttrs(); 
}), 

如果我試圖將其轉換爲一個計算性能似乎並不對屬性變化做任何事情,除非我刷新頁面之後,它已經過渡到'索引'路線。如果我嘗試僅使用0123.方法和this.get('session.isAuthenticated')邏輯,則仍然需要刷新頁面。

那我不理解如何使用Ember.computeddidReceiveAttrs()?有人能給我一個例子嗎?或者向我展示一種更有效的方式來完成我正在努力完成的任務?

更新的代碼:

export default Ember.Component.extend({ 
    layout, 
    session: Ember.inject.service(), 
    currentUser: Ember.inject.service(), 
    user: null, 
    isAuthenticated: Ember.on('init', Ember.observer('session.isAuthenticated', function() { 
     this.get('currentUser').load().then(user => this.set('user', user)); 
    })), 
    currentUserFullName: Ember.computed.alias('user.fullName'), 
    tagName: 'navbar-main', 
    className: ['navbar', 'main'] 
}); 

因此,這是最少的代碼量,仍然使用觀測器和計算:

// app/pods/components/navbar-main/component.js 
import Ember from 'ember'; 
import layout from './template'; 

export default Ember.Component.extend({ 
    layout, 
    session: Ember.inject.service(), 
    currentUser: Ember.inject.service(), 
    user: null, 
    isAuthenticated: Ember.observer('session.isAuthenticated', function() { 
     this.get('currentUser').load().then(user => this.set('user', user)); 
    }), 
    currentUserFullName: Ember.computed.alias('user.fullName'), 
    tagName: 'navbar-main', 
    className: ['navbar', 'main'], 
    didReceiveAttrs() { 
     this._super(...arguments); 

     if(this.get('session.isAuthenticated')) { 
      this.isAuthenticated(); 
     } 
    } 
}); 

<!-- app/pods/components/navbar-main/template.hbs --> 
{{#if session.isAuthenticated}} 
    <div class="ui black user login label"> 
     <div class="ui grid"> 
      <div class="twelve wide column"> 
       <div class="detailed">{{currentUserFullName}}<br>Welcome</div> 
      </div> 
      <div class="four wide column" style="padding-top: 12px; margin-top: 0;"> 
       <img class="ui top aligned small avatar image" src="http://semantic-ui.com/images/avatar/small/christian.jpg"> 
       <!--<img class="ui top aligned tiny avatar image" src="{{currentUser.avatar}}">--> 
      </div> 
     </div> 
    </div> 
{{/if}} 

UPDATE 2(與來自@AdamCooper幫助和@kumkanillam最終代碼)方法,但不使用組件生命週期。所以我猜想仍然有必要使用觀察者,有時候是我想到的。

回答

3

當你要避免使用觀察家可能的時候一般規則。 Steffan Penner對觀察員有一個great video,我建議您注意真正理解他們爲什麼對您的代碼庫有潛在危險。

在你的情況下,load()函數返回一個承諾,這是不是你想從一個計算財產返還,所以你需要在isAuthenticated使用觀察的東西。 我已經簡化你的代碼,就像我可以不能夠運行,但希望你應該明白我的意思:

export default Ember.Component.extend({ 
    layout, 
    session: Ember.inject.service(), 
    currentUser: Ember.inject.service(), 

    user: null, 

    authenticatedObserver: Ember.observer('session.isAuthenticated', function() { 
     // Load the user, this will cause the currentUserFullName to be 
     // updated. We're using an observer here because load() returns 
     // a promise 
     this.get('currentUser').load().then(user => this.set('user', user)); 
    }), 

    // This computed property will be re-calculated whenever user is modified 
    currentUserFullName: Ember.computed.alias('user.fullName') 
}); 
+0

〜所以,基本上是同樣的事情,我已經聽到和讀到有關觀察員,但你的回答仍然使用一個觀察員?大聲笑。我能否假設這種特殊情況需要使用觀察者? – charlwillia6

+1

我只在必要時使用觀察者。這就是你的呼喚負載功能 –

+0

所以這個作品,如果我仍然使用'didReceiveAttrs(){ this._super(...參數); 如果(this.get( 'session.isAuthenticated')){ this.isAuthenticated(); }} ,',它肯定不會縮短了代碼,但我仍然不確定究竟怎麼回事,因爲如果我做了'this.get(「currentUserFullName」)」或一個'this.get(‘用戶’ )',我得到空值。我還必須將我的模板更改爲'{{#if session.isAuthenticated',而不是'{#if currentUser'來隱藏它綁定的元素。這聽起來正確嗎? – charlwillia6

1

灰燼將根據渲染場景調用的順序組件的生命週期掛鉤的方法。

在初始渲染 - 初始化,didReceiveAttrs,willRender,didInsertElement,didRender
在重新Rener - didUpdateAttrs,didReceiveAttrs,willUpdate,willRender,didRender
在組件銷燬 - willDestroyElement,willClearRender,didDestroyElement
(參考 - https://guides.emberjs.com/v2.7.0/components/the-component-lifecycle/

我們不應該調用這些組件生命週期鉤子方法。

我beleive,你可以完全隔離currentUser特定的代碼來currentUser服務,讓您可以輕鬆地注入並使用它的所有組件。

export default Ember.Component.extend({ 
    session: Ember.inject.service(), 
    currentUser: Ember.inject.service(), 
    currentUserFullName: Ember.computed.alias('currentUser.currentUserFullName'), 
    user: Ember.computed.alias('currentUser.user'), 

    tagName: 'navbar-main', 
    className: ['navbar', 'main'],  

}); 

通過觀察session.isAuthenticated屬性來初始化currentUser及其細節。

服務\電流user.js的

import Ember from 'ember'; 

export default Ember.Service.extend({ 
    session: Ember.inject.service(), 
    currentUserFullName: null, 
    user: null, 

    loadCurrentUserDetails:Ember.observer('session.isAuthenticated', function(){ 
    //load async data and set user and currentUserFullName. 
    }) 
}); 
+0

〜我想知道初始化,但還沒有真正涉及到初始化。我會研究這一點並回複評論。 – charlwillia6

+0

我實際上在我的項目中使用了一個ember插件節點包,它已經爲currentUser提供了一個服務,所以這不適合我。我不想改變它綁定的服務,但該服務正在使用計算屬性:'currentUserId:Ember.computed('session.data.authenticated',function(){var session = this.get( '會話');如果(session.get( 'isAuthenticated')){回報session.get( 'data.authenticated.id');}其他{返回NULL;}}),' – charlwillia6

+0

然後:'負載() {返回新Ember.RSVP.Promise((解析,拒絕)=> {風險currentUserId = this.get( 'currentUserId');如果(currentUserId){風險currentUser = this.get( '存儲')peekRecord('用戶',currentUserId); if(currentUser){resolve(currentUser);} else {this.get('store')。findRecord('user',currentUserId).then((user)=> resolve(user),reject) ;}} else {reject();}});}',因此,使用這個已經存在的服務,我使用了上面的@AdamCooper的建議,並且還添加了一個'didReceiveAttrs()'函數來實現它的工作。 。這是最好的方法嗎? – charlwillia6