天天看點

NgRx Store裡的StoreModule.forRoot()

NgRx Store is mainly for managing global state across an entire application. In cases where you need to manage temporary or local component state, consider using NgRx ComponentStore.

NgRx Store是為了管理整個應用的全局狀态而設計的,如果想管理局部Component狀态或者臨時狀态,請使用NgRx ComponentStore.

NgRx Store裡的StoreModule.forRoot()

Actions are the inputs and outputs of many systems in NgRx.

Actions是NgRx系統的輸入和輸出。

NgRx裡标準的Action interface:

NgRx Store裡的StoreModule.forRoot()

export interface Action {
    type: string;
}      

NgRx reducer的immutability特性

Each action handles the state transition immutably. This means that the state transitions are not modifying the original state, but are returning a new state object using the spread operator. The spread syntax copies the properties from the current state into the object, creating a new reference.

狀态遷移并不會修改原始狀态,而是借助三個點 … 即spread操作符,傳回新的state對象。Spread 操作符會從目前state變量裡拷貝屬性,生成新的對象引用。

const scoreboardReducer = createReducer(
  initialState,
  on(ScoreboardPageActions.homeScore, state => ({ ...state, home: state.home + 1 })),
  on(ScoreboardPageActions.awayScore, state => ({ ...state, away: state.away + 1 })),
  on(ScoreboardPageActions.resetScore, state => ({ home: 0, away: 0 })),
  on(ScoreboardPageActions.setScores, (state, { game }) => ({ home: game.home, away: game.away }))
);
export function reducer(state: State | undefined, action: Action) {
  return scoreboardReducer(state, action);
}      

When an action is dispatched, all registered reducers receive the action. Whether they handle the action is determined by the on functions that associate one or more actions with a given state change.

The state of your application is defined as one large object.

Registering reducer functions to manage parts of your state only defines keys with associated values in the object. To register the global Store within your application, use the StoreModule.forRoot() method with a map of key/value pairs that define your state.

The StoreModule.forRoot() registers the global providers for your application, including the Store service you inject into your components and services to dispatch actions and select pieces of state.

StoreModule.forRoot 為應用注冊全局的服務提供者,包括注入到Component裡的Store服務,以及用于dispatch actions的service以及選擇state片段的服務。

Registering states with StoreModule.forRoot() ensures that the states are defined upon application startup. In general, you register root states that always need to be available to all areas of your application immediately.

使用StoreModule.forRoot注冊的states,在應用startup之後立即處于可用狀态。如果一個state在應用啟動後,需要迅速被應用各個部分使用,那麼需要注冊成root state.

feature state

Feature states behave in the same way root states do, but allow you to define them with specific feature areas in your application. Your state is one large object, and feature states register additional keys and values in that object.

下面的代碼,給應用注冊了一個空的root state:

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';

@NgModule({
  imports: [
    StoreModule.forRoot({})
  ],
})
export class AppModule {}      

feature module的注冊方法:

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import * as fromScoreboard from './reducers/scoreboard.reducer';

@NgModule({
  imports: [
    StoreModule.forFeature(fromScoreboard.scoreboardFeatureKey, fromScoreboard.reducer)
  ],
})
export class ScoreboardModule {}      

隻要在app.module.ts裡将包含了上述feature state的module import,就能做到feature state的eager import:

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { ScoreboardModule } from './scoreboard/scoreboard.module';

@NgModule({
  imports: [
    StoreModule.forRoot({}),
    ScoreboardModule
  ],
})
export class AppModule {}      

selector

Selectors are pure functions used for obtaining slices of store state.

純函數,唯一作用就是獲得store state的片段資料。

Selectors provide many features when selecting slices of state:

Portability

Memoization

Composition

Testability

Type Safety

When using the createSelector and createFeatureSelector functions @ngrx/store keeps track of the latest arguments in which your selector function was invoked.

使用createSelector和createFeatureSelector之後,ngRx架構代碼會記錄當我們的selector被調用時,傳入的輸入參數。這麼做的動機是,selectors是純函數,是以相同的輸入一定會産生相同的輸出,是以ngRx把每次輸入以及輸出都緩存起來,如果下次調用selector的輸入在緩存裡有記錄,即從緩存裡傳回輸出資料,以提高性能。

這種行為稱為memoization.

下圖的代碼,調用createFeatureSelector傳入一個字元串,建立一個feature selector:

NgRx Store裡的StoreModule.forRoot()

傳回類型為MemoizedSelector,即帶有記憶功能的selector.

createSelector的輸入參數,以及傳回的類型仍然是selector:

NgRx Store裡的StoreModule.forRoot()

createSelector支援傳入多達8個selector,來實作更複雜的取數邏輯。看個例子:

The createSelector function can take up to 8 selector functions for more complete state selections.

For example, imagine you have a selectedUser object in the state. You also have an allBooks array of book objects.

And you want to show all books for the current user.

import { createSelector } from '@ngrx/store';

export interface User {
  id: number;
  name: string;
}

export interface Book {
  id: number;
  userId: number;
  name: string;
}

export interface AppState {
  selectedUser: User;
  allBooks: Book[];
}

export const selectUser = (state: AppState) => state.selectedUser;
export const selectAllBooks = (state: AppState) => state.allBooks;

export const selectVisibleBooks = createSelector(
  selectUser,
  selectAllBooks,
  (selectedUser: User, allBooks: Book[]) => {
    if (selectedUser && allBooks) {
      return allBooks.filter((book: Book) => book.userId === selectedUser.id);
    } else {
      return allBooks;
    }
  }
);      

The createFeatureSelector is a convenience method for returning a top level feature state. It returns a typed selector function for a feature slice of state.

繼續閱讀