※ 引述《heavenbetula (綠草)》之銘言:
: 大家好~小弟是Angular剛接觸沒多久的新手
: 最近在使用Service在路由間跳轉時遇到一些問題
: https://stackblitz.com/edit/angular-w3njbx
: ↑上面的程式,我在child1 component中訂閱了service裡的Subject物件,
: 而在child2 component的按鈕按下後,才會接收到觸發了,而去做後續行為
: 這個例子中,我預期的就是按鈕每按一次,我就console.log一次,
: 但是我發現,在路由跳轉的過程中,只要child2 component進入一次
: 就會連同上次的紀錄都留著,也就是說:
: 第一次進入child2 component按下按鈕一次,console.log一次(正常)
: 先按連結離開child2 component
: 第二次再進入child2 compoent按下按鈕一次,console.log直接跳出兩次結果
: 先按連結離開child2 component
: 第三次再進入child2 component按下按鈕一次,console.log直接跳出三次結果
: 請問為什麼會這樣呢?
你在Child1Component中用constructor injection注入service
因為Angular的DI機制,沒特別設定Injector的話service會從component開始往上找
然後你的FooteractionService只有由AppModule做Provider
所以service的instance是singleton
每次切換路由時會建立/消滅Component
每次切換到Child1的路由時都會產生一個Child1的instance
並且每次注入的都是同一個service
訂閱的也都是同一個service裡的subject
訂閱寫在constructor裡每次Child1產生一次就訂閱一次
呼叫service.action()的時候因為之前的訂閱沒有被取消掉,
自然會重複觸發subscribe()裡面的callback
目前普遍建議的做法大概是這樣
在Child1中給一個$destroy的property = new Subject<void>();
Class implements OnDestroy
在生命週期方法內做$destroy.next()和$destroy.unsubscribe()
然後在訂閱service內subject的時候不要直接訂閱
用subject.pipe(takeUntil(this.$destroy)).subscribe()
這樣Child1因為路由變更消滅後
訂閱的subject發送時就不會觸發該次的subscribe()裡面的callback
如果上面的原理看不懂的話就抄最後的程式碼就好了
但是如果要繼續玩Angular甚至拿它來做大專案
還是要了解一下他的routing跟DI 還有RxJS的原理以及operators
這樣過程會比較愉快一點