ngrx /存储状态从选择器内更新

时间:2017-03-20 14:33:27

标签: angular rxjs 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也在修改状态。结果,我不再拥有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'
                    }
                }]
             }
        }
    }
}

对我来说这是一个意想不到的行为。或者我可能缺少一些反应性教程?

1 个答案:

答案 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冻结库,如果商店发生变异,将会产生错误。