2017-03-20 38 views
1

我有以下歸一化的狀態的結構:NGRX /存儲狀態更新

auth: { 
    user: string; // this is the current logged in uid 
}; 
entities: { 
    users: { [key: string]: User } // normalized user entities (including the current user) 
}; 

User接口(注意到朋友陣列):

{ 
    _id: string; 
    name: string; 
    friends: Array<{ 
     status: string; 
     user: string | User; // uid or user object 
    }> 
} 

AuthService,我有當前用戶的選擇器:

this.user$ = Observable.combineLatest(
    store.select(state => state.auth.user), 
    store.select(state => state.entities.users), 
    (id, users) => id && users[id] || {} 
); 

FriendsService,我對用戶的填充朋友選擇:

this.mates$ = this.authService.user$ 
    .withLatestFrom(
     this.store.select(state => state.entities.users), 
     (user, users) => 
      (user.friends || []).map(f => { 
       f.user = typeof f.user === 'string' 
        ? users[<string>f.user] 
        : users[f.user._id]; 
       return f; 
      }) 
    ); 

的問題是,從mates$選擇FN的投影也修改狀態。其結果是,我不再有標識,但在我的朋友陣列的整體用戶對象:

國家WITHOUTmates$選擇:

{ 
    auth: { 
     user: '5706a6de1fcf42ec245abeea' 
    }, 
    entities: { 
     users: { 
      5706a6de1fcf42ec245abeea: { 
       _id: '5706a6de1fcf42ec245abeea', 
       name: 'Nikola', 
       friends: [{ 
        status: 'requested', 
        friend: '57224d106864441c32e6a5b6' 
       }] 
      } 
     } 
    } 
} 

國家mates$選擇:

{ 
    auth: { 
     user: '5706a6de1fcf42ec245abeea' 
    }, 
    entities: { 
     users: { 
      5706a6de1fcf42ec245abeea: { 
       _id: '5706a6de1fcf42ec245abeea', 
       name: 'Nikola', 
       friends: [{ 
        status: 'requested', 
        friend: { 
         _id: '57224d106864441c32e6a5b6', 
         name: 'Friend01' 
        } 
       }] 
      } 
     } 
    } 
} 

這對我來說是一個意想不到的行爲。或者,我可能缺少一些反應式教程?

回答

3
this.mates$ = this.authService.user$ 
    .withLatestFrom(
    this.store.select(state => state.entities.users), 
    (user, users) => 
    // YOU SHOULDN'T UPDATE DATA FROM THE STORE OUTSIDE A REDUCER 
    // ----------------------------- 
    (user.friends || []).map(f => { 
     f.user = typeof f.user === 'string' 
     ? users[<string>f.user] 
     : users[f.user._id]; 
     return f; 
    }) 
    // ----------------------------- 
); 

相反,你應該對這樣的

this.mates$ = this.authService.user$ 
    .withLatestFrom(
    this.store.select(state => state.entities.users), 
    (user, users) => 
    // NEW REF TO AVOID STATE MUTATION 
    // ----------------------------- 
    (user.friends || []) 
     .map(f => Object.assign({}, f, { updatedPropHere: null })) 
    // ----------------------------- 
); 

一個新的參考合作,以確保你不會從你的商店變異數據,你可能想看看進入終極版冷凍庫,如果商店發生了變異,將會拋出一個錯誤。

+0

但我認爲'f'已經是一個副本了,因爲'Array.map()'正在返回一個新的數組? – Nikola

+1

@尼古拉是和不。當你使用'Array.map'時,它會創建一個**新數組**,並將你正在循環的每個項目都推送到這個新數組中。但是它並沒有對你正在循環的項目進行深層次的複製。如果你操作的是原始類型,它會沒問題,但因爲它是一個對象,所以你仍然在使用同一個對象;) – Maxime

+0

這有助於解決我自己的問題,我無意中在選擇器映射函數中突變了狀態。在此之後,我開始使用ngrx-store-freeze在將來幫助解決這個問題 –