angular ngrx
NgRx framework helps to build reactive angular applications.
NgRx框架有助于构建React性角度应用程序。
NgRx Store provides reactive state management for the angular application. NgRx store is the redux implementation developed specifically for angular applications and provides RxJS observable API.
NgRx Store为角度应用程序提供React状态管理。 NgRx存储是专门为角度应用程序开发的redux实现,并提供RxJS可观察的API。
The state is an immutable data structure that is a single source of truth for the whole application.
状态是一个不变的数据结构,是整个应用程序的单一事实来源。
NgRx Actions represent the unique events in the application which may be used to perform state transition or trigger side-effects.
NgRx动作表示应用程序中的唯一事件,可用于执行状态转换或触发副作用。
NgRx Reducers are pure functions that react to
Actions
to perform state transitions.NgRx Reducers是纯函数,对
Actions
做出React以执行状态转换。NgRx Selectors are pure functions that select, derive, or compose a slice of the state.
NgRx选择器是用于选择,派生或组成状态切片的纯函数。
NgRx Effects allow the isolation of side-effects.
NgRx效果可隔离副作用。
先决条件 (Prerequisites)
- you have a fair understanding of the angular framework.您对角度框架有相当的了解。
- You have a basic understanding of redux architecture. 您对redux架构有基本的了解。
you have a fair knowledge of
RxJS
Observable API and various operators.您对
RxJS
Observable API和各种运算符有一定的了解。
安装 (Installation)
If you already have an angular app, you can directly go to step — 4
如果您已经有一个角度应用程序,则可以直接转到步骤4
# 1) install angular cli
npm install -g @angular/cli
# 2) create a demo app
ng new ngrx-angular-demo
# 3) navigate to demo app
cd ngrx-angular-demo
# 4) install ngrx store
ng add @ngrx/store@latest
# 5) run angular in dev mode
ng serve
To begin with, let us have a look at an example file structure. A structure like this would be helpful to split up each feature of NgRx
state management in your app. I usually replicate the same structure in each feature module.
首先,让我们看一个示例文件结构。 这样的结构有助于在应用程序中拆分NgRx
状态管理的每个功能。 我通常在每个功能模块中复制相同的结构。
──store
|_ app.actions.ts
|_ app.effects.ts
|_ app.reducer.ts
|_ app.selectors.ts
app.actions.ts
file will contain theNgRX actions
app.actions.ts
文件将包含NgRX actions
app.effects.ts
file will contain theNgRx effects
.app.effects.ts
文件将包含NgRx effects
。app.reducer.ts
file will contain theState
design and its initialization. it will also contain a reducer function.app.reducer.ts
文件将包含State
设计及其初始化。 它还将包含一个reducer函数。app.selectors.ts
will contain theNgRx selectors
.app.selectors.ts
将包含NgRx selectors
。
Here is the complete project setup.
这是完整的项目设置。
州 (State)
The state represents an immutable object that contains the state of an application. It is read-only, so every state transition will return a new state rather than modifying the existing state. As the application grows, each feature should contain a separate state which are part of the global app state. As such, the application state contains one or more feature states.
状态代表包含应用程序状态的不可变对象。 它是只读的,因此每个状态转换都将返回新状态,而不是修改现有状态。 随着应用程序的增长,每个功能都应包含一个单独的状态,这些状态是全局应用程序状态的一部分。 这样,应用程序状态包含一个或多个功能状态。
The state is similar to Javascript
objects. It contains the feature states as the key-value
pairs where the key
represent a feature state and the value
is the feature state object.
状态类似于Javascript
对象。 它包含功能状态作为key-value
对,其中key
表示功能状态, value
是功能状态对象。
The state related to a feature module is referred to as feature state
.
与功能模块有关的状态称为feature state
。
interface State{
feature_1: FeatureOneState,
feature_2: FeatureTwoState,
feature_3: FeatureThreeState
}
Let’s assume, our angular application has many feature modules. One of the features is responsible for the user’s profile. The profile
module is responsible for rendering the list of users
and the related posts
.
假设我们的角度应用程序具有许多功能模块。 功能之一是负责用户的个人资料。 profile
模块负责呈现users
列表和相关posts
。
To design the state, we can assume that the state required for the profile module should contain a list of users and List of posts. Let’s call the profile state as ProfileFeatureState
.
为了设计状态,我们可以假设个人档案模块所需的状态应包含用户列表和帖子列表。 让我们将概要文件状态称为ProfileFeatureState
。
/** User modal */
export interface User {
id: number;
email: string;
first_name: string;
last_name: string;
avatar: string;
}
/** post modal **/
export interface Post {
id: number;
userId: number;
title: string;
body: string;
}
/** the modals should ideally be in their own ts file**/
export interface ProfileFeatureState {
users: User[];
posts: Post[];
}
We defined the type for User
and Post
and also created an interface for ProfileFeatureState
.
我们为User
和Post
定义了类型,还为ProfileFeatureState
创建了一个接口。
interface AppState{
profile: UserFeatureState,
//..other features here
}
Finally, we would add ProfileFeatureState
to applications root state - AppState
. The profile
key represents the profileFeatureState
.
最后,我们将增加ProfileFeatureState
到应用程序根状态- AppState
。 profile
键表示profileFeatureState
。
初始化状态 (Initializing the state)
export const initialProfileFeatureState: ProfileFeatureState = {
users: null,
addresses: null
};
Initially, the state of the application is null
since there would be no data. As such, both the users array
and posts array
would be initialized to null
.
最初,由于没有数据,因此应用程序的状态为null
。 这样, users array
和posts array
都将初始化为null
。
At this point, app.reducer.ts
file should look like -
此时, app.reducer.ts
文件应如下所示:
/*app.reducer.ts*/
/** User modal */
export interface User {
id: number;
email: string;
first_name: string;
last_name: string;
avatar: string;
}
/** Post Modal */
export interface Post {
id: number;
userId: number;
title: string;
body: string;
}
export interface ProfileFeatureState {
users: User[];
addresses: Address[];
}
export const initialProfileFeatureState: ProfileFeatureState = {
users: null,
addresses: null
};
export interface AppState {
profile: ProfileFeatureState;
}
NgRx动作(NgRx Actions)
NgRx Actions represent events in the application. They may trigger a state transition or trigger a side-effect in NgRx Effect
services.
NgRx动作表示应用程序中的事件。 它们可能会触发状态转换或触发NgRx Effect
服务中的NgRx Effect
。
The Action
interface contains a property called Type
. The Type
property identifies the action. Actions can also contain optional metadata
.
Action
接口包含一个名为Type
的属性。 Type
属性标识动作。 操作还可以包含可选的metadata
。
interface Action{
type:string
//optional metadata properties
}
CreateAction函数(CreateAction function)
createAction function
is used to create the actions and it returns an ActionCreator function. ActionCreator
function, when called, returns an action of type TypedAction
. Optionally, we can also supply additional metadata using the props function.
createAction function
用于创建动作,它返回一个ActionCreator函数。 ActionCreator
函数时,将返回TypedAction
类型的TypedAction
。 (可选)我们还可以使用props函数提供其他元数据。
Let’s go ahead and create an action to add users to ProfileFeatureState
.
让我们继续并创建一个将用户添加到ProfileFeatureState
。
export const addUsers = createAction(
'[profile] add users',
props<{ users: User[] }>()
);
Notice the type of addUsers action is [profile] add users
. The [profile]
represents the source of action. Also, the props contain the array of users as the metadata.
请注意, addUsers操作的类型为[profile] add users
。 [profile]
代表动作的来源。 而且,道具包含用户数组作为元数据。
Similarly, we can create an action for adding posts to the feature state.
同样,我们可以创建一个将帖子添加到功能状态的动作。
//file: app.actions.ts
export const addPosts = createAction(
'[profile] add posts',
props<{ posts: Post[] }>()
);
addPosts action is dispatched to indicate that the Posts should be added to the state. It will also contain Post[]
metadata.
分派addPosts操作以指示应将Posts添加到状态。 它还将包含Post[]
元数据。
Actions represent the events and not the commands or operations . A single command or operation may generate many types of Actions. For example: An operation which creates a new user would atleast generate Actions for success and failure such as
[profile] user created
or[profile] user creation failed
.动作代表事件,而不代表命令或操作。 单个命令或操作可能会生成多种类型的动作。 例如:创建新用户的操作至少会生成成功和失败的操作,例如
[profile] user created
或[profile] user creation failed
。
NgRx减速器 (NgRx Reducers)
Reducers are pure functions that perform transitions from one state to another state based on the latest action dispatched. The reducer functions do not modify the existing state, rather it returns a new state for every state transition. Hence all the reducer functions perform immutable operations.
精简器是纯函数,可根据分派的最新操作执行从一种状态到另一种状态的转换。 Reducer函数不会修改现有状态,而是会为每个状态转换返回一个新状态。 因此,所有的reducer函数都执行不变的操作。
createReducer函数 (createReducer function)
NgRx provides a createReducer function to create reducers. It takes initialState
as the first param and any
number of on
functions. The on
function provides an association between actions and the state changes.
NgRx提供了createReducer函数来创建减速器。 它以initialState
作为第一个参数以及any
数量的on
函数。 on
功能提供了动作与状态更改之间的关联。
When an action is dispatched, all the reducers receive the action. The on
function mapping determines whether the reducer should handle the action.
分派动作后,所有的减速器都会收到该动作。 在on
函数映射确定减速是否应该处理的动作。
createReducer
function returns an ActionReducer function . ActionReducer function takes an Action and a State as input and returns a new computed State.
createReducer
函数返回一个ActionReducer函数。 ActionReducer函数将一个Action和一个State作为输入,并返回一个新的已计算State。
Let’s go ahead a create reducer which handles transitions for ProfileFeatureState
. createReducer
function can map many actions and return an ActionReducer
function.
让我们继续创建一个create reducer,它处理ProfileFeatureState
转换。 createReducer
函数可以映射许多动作并返回一个ActionReducer
函数。
import * as AppActions from './app.actions';
const theProfFeatureReducer = createReducer(
initialProfileFeatureState,
on(AppActions.addUsers, (state, { users }) => ({
...state,
users: [...users]
})),
on(AppActions.addPosts, (state, { posts }) => ({
...state,
posts: [...posts]
})),
);
The […]
spread operator
copies the properties of the object and returns a new object. It only performs the shallow copying and does not copy the nested structures. You should always consider a better alternative if you are dealing with a state that contains nested data structures. Libraries like lodash provide methods to clone nested structures.[…]
spread operator
复制对象的属性并返回一个新对象。 它仅执行浅表复制,不复制嵌套结构。 如果要处理包含嵌套数据结构的状态,则应始终考虑使用更好的选择。 像lodash这样的库提供了克隆嵌套结构的方法。
ActionReducerMap
provides the mapping as key-value
pairs where the key
represents the feature name as a string and the value
is the ActionReducer function
returned by createReducer
function.
ActionReducerMap
将映射作为key-value
对提供,其中key
将功能名称表示为字符串,而value
是createReducer
函数返回的ActionReducer function
函数。
In our case, the ActionReducerMap
will contain profile
as a key and value
as theProfFeatureReducer
.
在我们的示例中, ActionReducerMap
将包含profile
作为键,并将value
包含在theProfFeatureReducer
。
/**The profileFeatureReducer function is necessary as function calls are not supported in the View Engine AOT compiler. It is no longer required if you use the default Ivy AOT compiler (or JIT)**/
function profileFeatureReducer
(state: ProfileFeatureState = initialState, action: Action) {
return theProfFeatureReducer(state, action);
}
/** AppActionReducer Map**/
export const AppActionReducerMap: ActionReducerMap<AppState> = {
profile: profileFeatureReducer
// ... other feature go here
};
It is not necessary to create an ActionReducerMap
. You can directly provide the mapping in StoreModule.forRoot({key: ActionReducer})
while registering the reducer in app.module.ts. You can also separately register the feature state in the feature module. I prefer creating the ActionReducerMap
separately as it provides a better type checking in Typescript.
不必创建ActionReducerMap
。 您可以在StoreModule.forRoot({key: ActionReducer})
直接提供映射,同时在app.module.ts中注册化简器。 您也可以在功能模块中单独注册功能状态。 我更喜欢单独创建ActionReducerMap
因为它在Typescript中提供了更好的类型检查。
At this point, our app.reducer.ts
file should look like :
此时,我们的app.reducer.ts
文件应如下所示:
/** app.reducer.ts **/
export interface ProfileFeatureState {
users: User[];
posts: Post[];
}
export const initialProfileFeatureState: ProfileFeatureState = {
users: null,
posts: null
};
export interface AppState {
profile: ProfileFeatureState;
}
const theProfFeatureReducer = createReducer(
initialProfileFeatureState,
on(AppActions.addUsers, (state, { users }) => ({
...state,
users: [...users]
})),
on(AppActions.addPosts, (state, { posts }) => ({
...state,
posts: [...posts]
}))
);
function profileFeatureReducer(state: ProfileFeatureState = initialProfileFeatureState, action: Action) {
return theProfFeatureReducer(state, action);
}
export const AppActionReducerMap: ActionReducerMap<AppState> = {
profile: profileFeatureReducer
};
注册州(Register the State)
Once the reducer is created, It should be registered in the Module.The state can be registered using one of the two options:
创建减速器后,应将其注册在模块中。可以使用以下两个选项之一来注册状态:
注册根状态 (Register Root state)
To register the global store in the application, StoreModule.forRoot()
takes ActionReducerMap
as an argument. The map contains key
and ActionReducer
Object returned by createReducer
function.
要在应用程序中注册全局存储, StoreModule.forRoot()
将ActionReducerMap
作为参数。 该映射包含由createReducer
函数返回的key
和ActionReducer
对象。
分别注册每个功能状态- (Register each feature state separately -)
Feature states are similar to root states but they represent the state of specific features of an application. Typically, each feature should be registered in its own module.
功能状态类似于根状态,但是它们表示应用程序特定功能的状态。 通常,每个功能都应在其自己的模块中注册。
//Register root state
StoreModule.forRoot({ AppActionReducerMap })
//register the feature state
StoreModule.forFeature({ profile: profileFeatureReducer })
If you have come this far. You might also want to read about NgRx Selectors.
如果您走了这么远。 您可能还想阅读有关NgRx选择器的信息。
How to create NgRx Selectors
如何创建NgRx选择器
How to use createSelector function to compose selectors with single or multiple slices of state
如何使用createSelector函数组成具有单个或多个状态切片的选择器
How to use a projector function to return only a part within the slice of state.
如何使用投影仪功能仅返回状态切片中的一部分。
NgRx selectors are used to select a slice of state. I have a detailed post about it here.
NgRx选择器用于选择状态切片。 我在这里有详细的帖子。
This post was originally posted on initgrep.com
此帖子最初发布在initgrep.com上
angular ngrx