……状态到底是做什么的?

What does ...state do exactly?

我正在尝试 Angular 中的 NgRx (redux) 和下面示例中的 ...state,我无法完全理解。我搜索了一下,一般理解为传播,但不确定为什么 Interface State 中的数据属性在 reducer 的 switchreturn{} 块中重复,因为 ... 传播 无论如何?谁能帮我理解一下?

export interface State {
  sessionData: Map<string, string>;
  requesting: boolean;
  hasError: boolean;
  status: StatusModel;
}

export function sessionReducer(state: State = INITIAL_STATE, action: Session.Actions): State {
      switch (action.type) {
        case Session.REQUEST_SESSION_DATA:
          return {
            ...state,
            requesting: true,
            hasError: false,
            status: undefined,
          };
      }
}

PS:我查看了线程 ,通常得到的传播正是这样,传播开来。但是在 Redux/NgRx 的上下文中,试图理解为什么 return{} 具有 ...state 和三个附加属性。

... 被称为 spread operator.

展开运算符 "unpacks" 来自该对象的所有内容。

return {
    ...state,
    requesting: true,
    hasError: false,
    status: undefined,
};

相同
return {
    sessionData: state.sessionData,
    requesting: state.requesting,
    hasError: state.hasError
    status: state.status,
    requesting: true,
    hasError: false,
    status: undefined,
};

你是对的,这是 spread operator。基本上,它提取给定对象的所有属性。另一种写法是:

let newState = {
  sessionData: state.sessionData,
  requesting: state.requesting,
  hasError: state.hasError,
  status: state.status
};
newState.requesting = true;
newState.hasError = true;
newState.status = undefined;
return newState;

传播运算符让您无需费力了解所有属性的名称,并确保您未更改的所有值都按原样保留。

换句话说

{ ...state }

制作 state 的浅拷贝。然后您可以随意修改该浅拷贝。

状态的要点是它是不可变的(新对象是 returned,而不是修改过的对象)。因此,如果您想修改状态并向其添加新值,您需要 return 当前状态加上您想要添加到先前状态的新值。在使用展开运算符 ... 的示例中,您正在 return 创建一个新的不可变对象,其中包含先前的状态以及三个新属性 requestinghasErrorstatus .你可以这样想:

export function sessionReducer(state: State = INITIAL_STATE, action: Session.Actions): State {
      switch (action.type) {
        case Session.REQUEST_SESSION_DATA:
          state.requesting = true;
          state.hasError: false;
          state.status: undefined;

          return state;
      }
}

但是你不能这样做,因为你打破了国家的哲学,新的不可变对象而不是修改过的对象:)

在你的例子中,我们需要知道INITIAL_STATE是如何初始化的,但我认为它只包含sessionData 属性。因此,在该示例中,您正在 returning sessionData 加上其余属性。

在下面的 link 中,您可以看到扩展运算符是 Redux 世界中常用的运算符,用于 return 当前状态作为新对象(这是一个 Redux for React 示例,但它在 Angular).

中完全一样

在 Angular 中,这是一个非常常见的模式,使用 Redux 模式和 OnPush 变化检测策略,因为你告诉 Angular 只检查参考变化在组件 @Input 中,而不是将 属性 与 属性 比较的对象进行比较。这在性能上是一个很大的优势。

Use of Spread Operator with Redux

这是说 return 一个具有状态所有属性的新对象,并添加/修改 3 个附加属性。

值得知道 {...state} 深度等于 state 这样:

_.isEqual(state, {...state}) // returns true

但是:

{...state} !== state

这是因为 {} 创建了一个新对象,而传播运算符只是向该对象添加了 props。因此,state 的对象引用和新的对象引用是不一样的。这就是变化检测通常的工作方式。它查看对象引用是否已更改。如果有,它知道有变化并相应地采取行动。使用这种方法的原因是因为它比检查深度相等要快得多,因此您必须检查所有属性。

Reducers 经常使用扩展运算符,他们只想修改状态的一个属性。如果他们这样做:

state.requesting = true
return state

然后在这个例子中,对象引用没有改变,因此变化检测没有启动,你被塞满了。

为了强制更改检测,有一个名为 ngrx-store-freeze 的很棒的小库,它可以防止您意外改变状态,这会导致许多难以重现的错误。这个库实际上是 Udemy 在他们的 ngrx 付费课程中推荐的。