[英]angular async pipe not updating the view
我的問題可以通過與ngrx文檔的選擇器示例進行類比來最好地描述,以使事情保持簡單( https://github.com/ngrx/platform/blob/master/docs/store/selectors.md#using-selectors-for多件狀態 )。
我使用異步管道來訂閱某些狀態切片,例如使用選擇器進行選擇
this.visibleBooks$ = this.store$.select(selectVisibleBooks)
問題是,如果allBooks
數組是“ small”(小於100個項目),則我的視圖會立即更新。 但是,當它大於100時,我的視圖僅在下次觸發更改檢測(例如通過滾動)時才更新。 這是非常糟糕的用戶體驗,僅在滾動列表后才能看到書籍。
我看了異步管道的源代碼( https://github.com/angular/angular/blob/master/packages/common/src/pipes/async_pipe.ts ),實際上_updateLatestValue
方法調用_updateLatestValue
ChangeDetectorRef.markForCheck()
,據我所知,它會在下次觸發更改檢測時將要檢查的組件標記為更改。
我目前的解決方法是在頂級組件中手動訂閱
this.store$.select(selectVisibleBooks).subscribe(cb)
並在回調中手動調用ChangeDetectorRef.detectChanges()
。
我發現這並不令人滿意,並且無論Book[]
數組有多大,都希望異步管道始終運行。 有人對我可以做一些建議或糾正嗎?
根據要求編輯
如上所述,上面的“書店”案例只是我為簡化程序而編寫的應用程序的類比。 實際上,我的應用程序渲染圖的節點和邊緣,其中節點和邊緣還附加有一個稱為“ vnode”的版本,該版本與“ vedge”一起跨越了一個版本樹。 因此,任何圖元素都有其自己的版本樹。
我當前正在開發的是一個搜索表單,我們在其中向后端發送特定請求,以向其詢問與一組特定搜索鍵/值對匹配的任何節點。
因此,這些節點將隨后呈現在組件<nodes-list>
,我們通過輸入綁定傳遞節點
<nodes-list [nodes]="nodes$ | async"></nodes-list>
nodes-list
具有“按入”更改檢測功能,而頂級<search>
組件具有默認策略。
在ngOnInit()
中將nodes$
設置為
this.nodes$ = this.store$.select(selectFullNodesList)
selectFullNodesList
看起來像這樣:
export const fullNodesSelector = getFullNodesSelector(createSelector(selectSearchState, s => {
if (s.currentId) {
const nodes = s.queries.get(s.currentId).nodes;
if (nodes) {
return [...nodes];
}
}
return null;
}))
export const selectFullNodesList = createSelector(
fullNodesSelector,
(global: GlobalState) => global.data.counts,
createSelector(selectSearchState, s => s.sort),
(nodes, counts, sorting) => {
if (!nodes || !counts || !sorting) return null;
return [...nodes.sort(sorting.sortCbFactory(counts))];
}
)
讓我解釋:
getFullNodesSelector(...)
我將在下面顯示,它位於頂級庫中,因為我們可能會在許多功能中重復使用它。 但是它的作用是,它以另一個選擇器作為參數,該選擇器指向節點和vnode密鑰對{key: number, vKey: number}[]
數組,並將該數組轉換為附加了vnode的節點數組(請參閱下面的方法)。 search
功能的狀態,如果存在currentId
,這是當前請求到后端的ID,那么我們選擇作為當前請求結果的節點。 s.queries
是一個圍繞Javascript對象的輕量包裝程序,它使我可以輕松獲取/設置值,克隆或向克隆添加新項目。 當在NGRX中使用鍵/值存儲時,這對我很有幫助。 因此, s.queries.get(s.currentId).nodes
。 global.data.counts
只是每個節點有多少個鄰居的列表。 我想知道這一點,因為我想按“計數”對節點列表進行排序。 s.sort
是當前選擇列表的排序方式。 sortCbFactory
,該工廠僅返回正確的回調以傳遞給Array.sort
,但我需要在回調的本地范圍內顯示counts
,因為否則我將無法按計數進行排序。 selectSearchState
只是功能選擇器
export const selectSearchState = createFeatureSelector<SearchState>('search');
getFullNodesSelector(...)
看起來像這樣:
function getFullNodesSelector(keyPairsSelector: MemoizedSelector<object, GraphElementKeyPair[]>): MemoizedSelector<object, INodeJSON<IVNodeJSON>[]> {
return createSelector(
keyPairsSelector,
(s: GlobalState) => s.data.nodes,
(s: GlobalState) => s.data.vnodes,
(pairs, nodes, vnodes) => {
if (!pairs || !nodes || !vnodes) return null;
return pairs.map(pair => ({
...nodes.get(pair.key),
_SUB: {
...vnodes.get(pair.vKey)
}
}));
})
}
再次發表一些評論:
GraphElementKeyPair
( {key: number, vKey: number}
)數組 get
方法。 因此,由於我們已經使用異步管道訂閱了this.nodes$
,因此每次流<nodes-list>
上有一個新事件都應進行更新。 但是,實際上,這似乎取決於INodeJSON<IVNodeJSON>[]
的大小,並且如果數組的長度> INodeJSON<IVNodeJSON>[]
,我們必須通過單擊某個地方或滾動來手動觸發更改檢測。 對於較小的數組,應該自動刷新節點列表。
大型數據集不會有任何問題。 您的選擇器應該是同步的。 這意味着選擇器在運行時,在后台沒有其他任何事情發生。 不管在選擇器中計算所有內容需要花費多少時間,都可以。 如果花費的時間太長,您的瀏覽器可能會死機,僅此而已。
當你說
我使用了ngrx-store-freeze,它應該防止出現這種情況
It is not true.
從商店的角度來看,這是事實。 但是,讓我們想象一下:
您的商店有一個ID數組(比方說用戶ID)。
您有一個名為getAllUsers
的第一個選擇器。
這只是映射用戶ID並檢索正確的用戶,對嗎? 簽名為(usersIds: string[]): User[]
。
當然,在這里,您將創建一個新的數組引用,並且(不應該)使usersIds
數組發生突變。
但是,然后,您有了另一個選擇器。 getUsersResolved
基本上可以“解析”外部屬性。 假設用戶有動物列表。 從第一個選擇器中,您將獲得一個用戶列表,每個用戶都有一個animalsIds
屬性。 但是,您想要的是改為具有animals
數組。 如果從該選擇器中ngrx-store-freeze
了原始數組(來自第一個選擇器的數組),則ngrx-store-freeze
將不會引發任何錯誤,這是有道理的:您正在更改一個數組,但不是存儲中的一個數組。
那怎么可能是個問題呢?
getUsersResolved
,將其分配給一個變量,然后使用async
管道從視圖中訂閱該變量(假設這是您第一次在整個應用程序中訂閱它!) getAllUsers
由getUsersResolved
調用(首次)(也首次調用) getAllUsers
按預期創建一個新數組,並將其傳遞給getUsersResolved
。 因為這是第一次,即使您將該數組修改為getUsersResolved
,您也不會有任何問題:更改檢測將在第一次接收該數組時完成 getUsersResolved
將被觸發,但是如果您不尊重不變性並修改來自getAllUsers
的第一個數組,則該數組引用不會更改,並且更改檢測也不會發生。 而且,因為該數組不是商店的一部分,這是一個很好的選擇,它是由選擇器創建的數組 因此,我不確定您的問題是否來自那里,但是您可能要仔細檢查一下您是否尊重選擇器中的不變性。
最終,如果不確定,請共享selectVisibleBooks
的代碼, 以及它使用的每個選擇器 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.