……状态到底是做什么的?
What does ...state do exactly?
我正在尝试 Angular 中的 NgRx (redux) 和下面示例中的 ...state
,我无法完全理解。我搜索了一下,一般理解为传播,但不确定为什么 Interface State
中的数据属性在 reducer 的 switch
的 return{}
块中重复,因为 ... 传播 无论如何?谁能帮我理解一下?
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 创建一个新的不可变对象,其中包含先前的状态以及三个新属性 requesting
、hasError
和 status
.你可以这样想:
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
中,而不是将 属性 与 属性 比较的对象进行比较。这在性能上是一个很大的优势。
这是说 return 一个具有状态所有属性的新对象,并添加/修改 3 个附加属性。
值得知道 {...state}
深度等于 state
这样:
_.isEqual(state, {...state}) // returns true
但是:
{...state} !== state
这是因为 {}
创建了一个新对象,而传播运算符只是向该对象添加了 props。因此,state 的对象引用和新的对象引用是不一样的。这就是变化检测通常的工作方式。它查看对象引用是否已更改。如果有,它知道有变化并相应地采取行动。使用这种方法的原因是因为它比检查深度相等要快得多,因此您必须检查所有属性。
Reducers 经常使用扩展运算符,他们只想修改状态的一个属性。如果他们这样做:
state.requesting = true
return state
然后在这个例子中,对象引用没有改变,因此变化检测没有启动,你被塞满了。
为了强制更改检测,有一个名为 ngrx-store-freeze 的很棒的小库,它可以防止您意外改变状态,这会导致许多难以重现的错误。这个库实际上是 Udemy 在他们的 ngrx 付费课程中推荐的。
我正在尝试 Angular 中的 NgRx (redux) 和下面示例中的 ...state
,我无法完全理解。我搜索了一下,一般理解为传播,但不确定为什么 Interface State
中的数据属性在 reducer 的 switch
的 return{}
块中重复,因为 ... 传播 无论如何?谁能帮我理解一下?
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:我查看了线程 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 创建一个新的不可变对象,其中包含先前的状态以及三个新属性 requesting
、hasError
和 status
.你可以这样想:
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
中,而不是将 属性 与 属性 比较的对象进行比较。这在性能上是一个很大的优势。
这是说 return 一个具有状态所有属性的新对象,并添加/修改 3 个附加属性。
值得知道 {...state}
深度等于 state
这样:
_.isEqual(state, {...state}) // returns true
但是:
{...state} !== state
这是因为 {}
创建了一个新对象,而传播运算符只是向该对象添加了 props。因此,state 的对象引用和新的对象引用是不一样的。这就是变化检测通常的工作方式。它查看对象引用是否已更改。如果有,它知道有变化并相应地采取行动。使用这种方法的原因是因为它比检查深度相等要快得多,因此您必须检查所有属性。
Reducers 经常使用扩展运算符,他们只想修改状态的一个属性。如果他们这样做:
state.requesting = true
return state
然后在这个例子中,对象引用没有改变,因此变化检测没有启动,你被塞满了。
为了强制更改检测,有一个名为 ngrx-store-freeze 的很棒的小库,它可以防止您意外改变状态,这会导致许多难以重现的错误。这个库实际上是 Udemy 在他们的 ngrx 付费课程中推荐的。