更多 @ngrx/effects
More @ngrx/effects
我 asked a question 不久前围绕 @ngrx/effects
图书馆,但回复并没有完全解决我的问题。
我现在很高兴我理解了动作和效果是如何相互关联的,但我仍然不确定它们执行什么功能。 example app 在某种程度上帮助了我,但似乎效果正在做所有繁重的工作:例如,loadCollection$
效果似乎正在加载所有资源;随后发送 AddBookSuccessAction
似乎将这本书添加到 collection。
在此应用中,AddBookAction
似乎在减速器中不执行任何操作,但效果是加载资源并调度成功操作。
我想我真正想知道的是关注点分离:动作应该做什么,效果应该做什么?
当您将 @ngrx/effects
引入您的应用程序时,您需要有一点不同的想法。以登录组件和用户状态为例
@Component({})
class LoginComponent {
login(form: any) { // implementation }
}
@Component({})
class AppComponent {
user: Observable<User>;
constructor(store: Store<AppState>) {
this.user = store.select('user');
}
}
如果不使用效果,您的 login
实现可能类似于
login(form: any) {
this.authService.login(new Credentials(form))
.map(res => res.json() as User)
.subscribe(user => {
this.store.dispatch({ type: UPDATE_USER, payload: user });
});
}
当调用 dispatch
时,reducer 使用该操作来更新用户状态。所以这个动作并没有真正做任何事情。 reducer 可以根据操作使用有效负载来更新状态。订阅(在本例中)AppComponent
将获得更新的用户。
引入效果时,主要区别在于 login
的处理方式。 USER_UPDATED
操作 或 用户减速器没有任何变化。所发生的变化是您引入了另一个操作,该操作由 login
方法调度。所以现在你的新 login
就是
login(form: any) {
this.store.dispatch({ type: LOGIN, payload: form })
}
现在效果的目的是处理通常在 login
中处理的内容。它会监听 LOGIN
动作,然后将自己转换为 USER_UPDATED
动作。
@Injectable()
class LoginEffects {
constructor(private actions: Actions, private authService: AuthService) {}
@Effect
login$ = this.actions
.ofType(LOGIN)
.map(action => new Credentials(action.payload))
.switchMap(credentials => {
return this.authService.login(credentials)
.map(res => res.json() as User)
.map({ type: USER_UPDATED, payload: user })
});
}
你可以看到,从 LOGIN
动作中,我们得到了凭据,并使用 switchMap
到 return 不同的 Observable,一个包含新的(UPDATED_USER ) 行动。所以这只是一个转变。没有人必须调用效果。这是自动订阅的。
这样做的好处是,它使您的组件更简单,更易于测试。还将所有的副作用放在一个地方,这样更容易推理和测试。您的所有组件所做的就是订阅状态和调度操作。该效果将处理所有跑腿工作并分派适当的结果动作。
就"Action Classes"而言,这些都不是强制性的。 Action
只不过是一个具有两个属性 type
和 payload
的对象,它们被传递给 reducer。采取行动 类 的目的是充当行动 创作者 。例如
class UserActions {
static readonly USER_UPDATED = 'USER_UPDATE';
userUpdated(user: User): Action {
return {
type: UserActions.USER_UPDATED,
payload: user
}
}
}
现在您无需自己创建动作,只需调用适当的方法来获取动作
constructor(private userActions: UserActions) {}
@Effect
login$ = this.actions
.ofType(LOGIN)
.map(form => new Credentials(form))
.switchMap(credentials => {
return this.authService.login(credentials)
.map(res => res.json() as User)
.map(this.userActions.updateUser(user))
});
您可以看到我们创建 Action
的最后一个 map
调用只是调用 userActions.updateUser
。
这样做有一些好处。其一,你会得到强类型。当您自己创建操作时,您可能会传递错误的负载。但是当你有一个你知道参数类型需要是什么的方法时,你就不太可能出错。
此外,当您使用动作创建器时,您可以接受不同的参数。它不一定是有效载荷。这样您就可以以可重现和可测试的方式自己创建有效载荷(并可能引入一些逻辑)。
另请参阅:
我 asked a question 不久前围绕 @ngrx/effects
图书馆,但回复并没有完全解决我的问题。
我现在很高兴我理解了动作和效果是如何相互关联的,但我仍然不确定它们执行什么功能。 example app 在某种程度上帮助了我,但似乎效果正在做所有繁重的工作:例如,loadCollection$
效果似乎正在加载所有资源;随后发送 AddBookSuccessAction
似乎将这本书添加到 collection。
在此应用中,AddBookAction
似乎在减速器中不执行任何操作,但效果是加载资源并调度成功操作。
我想我真正想知道的是关注点分离:动作应该做什么,效果应该做什么?
当您将 @ngrx/effects
引入您的应用程序时,您需要有一点不同的想法。以登录组件和用户状态为例
@Component({})
class LoginComponent {
login(form: any) { // implementation }
}
@Component({})
class AppComponent {
user: Observable<User>;
constructor(store: Store<AppState>) {
this.user = store.select('user');
}
}
如果不使用效果,您的 login
实现可能类似于
login(form: any) {
this.authService.login(new Credentials(form))
.map(res => res.json() as User)
.subscribe(user => {
this.store.dispatch({ type: UPDATE_USER, payload: user });
});
}
当调用 dispatch
时,reducer 使用该操作来更新用户状态。所以这个动作并没有真正做任何事情。 reducer 可以根据操作使用有效负载来更新状态。订阅(在本例中)AppComponent
将获得更新的用户。
引入效果时,主要区别在于 login
的处理方式。 USER_UPDATED
操作 或 用户减速器没有任何变化。所发生的变化是您引入了另一个操作,该操作由 login
方法调度。所以现在你的新 login
就是
login(form: any) {
this.store.dispatch({ type: LOGIN, payload: form })
}
现在效果的目的是处理通常在 login
中处理的内容。它会监听 LOGIN
动作,然后将自己转换为 USER_UPDATED
动作。
@Injectable()
class LoginEffects {
constructor(private actions: Actions, private authService: AuthService) {}
@Effect
login$ = this.actions
.ofType(LOGIN)
.map(action => new Credentials(action.payload))
.switchMap(credentials => {
return this.authService.login(credentials)
.map(res => res.json() as User)
.map({ type: USER_UPDATED, payload: user })
});
}
你可以看到,从 LOGIN
动作中,我们得到了凭据,并使用 switchMap
到 return 不同的 Observable,一个包含新的(UPDATED_USER ) 行动。所以这只是一个转变。没有人必须调用效果。这是自动订阅的。
这样做的好处是,它使您的组件更简单,更易于测试。还将所有的副作用放在一个地方,这样更容易推理和测试。您的所有组件所做的就是订阅状态和调度操作。该效果将处理所有跑腿工作并分派适当的结果动作。
就"Action Classes"而言,这些都不是强制性的。 Action
只不过是一个具有两个属性 type
和 payload
的对象,它们被传递给 reducer。采取行动 类 的目的是充当行动 创作者 。例如
class UserActions {
static readonly USER_UPDATED = 'USER_UPDATE';
userUpdated(user: User): Action {
return {
type: UserActions.USER_UPDATED,
payload: user
}
}
}
现在您无需自己创建动作,只需调用适当的方法来获取动作
constructor(private userActions: UserActions) {}
@Effect
login$ = this.actions
.ofType(LOGIN)
.map(form => new Credentials(form))
.switchMap(credentials => {
return this.authService.login(credentials)
.map(res => res.json() as User)
.map(this.userActions.updateUser(user))
});
您可以看到我们创建 Action
的最后一个 map
调用只是调用 userActions.updateUser
。
这样做有一些好处。其一,你会得到强类型。当您自己创建操作时,您可能会传递错误的负载。但是当你有一个你知道参数类型需要是什么的方法时,你就不太可能出错。
此外,当您使用动作创建器时,您可以接受不同的参数。它不一定是有效载荷。这样您就可以以可重现和可测试的方式自己创建有效载荷(并可能引入一些逻辑)。
另请参阅: