我有以下规范化的状态结构:
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也在修改状态。结果,我不再拥有id,而是我的friends数组中的整个用户对象:
状态没有 mates$
选择器:
{
auth: {
user: '5706a6de1fcf42ec245abeea'
},
entities: {
users: {
5706a6de1fcf42ec245abeea: {
_id: '5706a6de1fcf42ec245abeea',
name: 'Nikola',
friends: [{
status: 'requested',
friend: '57224d106864441c32e6a5b6'
}]
}
}
}
}
状态 WITH mates$
选择器:
{
auth: {
user: '5706a6de1fcf42ec245abeea'
},
entities: {
users: {
5706a6de1fcf42ec245abeea: {
_id: '5706a6de1fcf42ec245abeea',
name: 'Nikola',
friends: [{
status: 'requested',
friend: {
_id: '57224d106864441c32e6a5b6',
name: 'Friend01'
}
}]
}
}
}
}
对我来说这是一个意想不到的行为。或者我可能缺少一些反应性教程?
答案 0 :(得分: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 }))
// -----------------------------
);
为了确保您不会改变商店中的数据,您可能需要查看redux冻结库,如果商店发生变异,将会产生错误。