当前位置: 首页 > 工具软件 > ngrx-actions > 使用案例 >

ngrx 入门---1、项目构建及无http请求组件实现

狄赞
2023-12-01

一、创建工程,搭建基本结构

计划:
1、创建一个angular模版的运用程序
2、引用bootstrap
3、引用@ngrx

1、创建工程

ng new pet-tags-ngrx

2、进入工程文件夹

cd pet-tags-ngrx

3、加入bootstrap

npm install bootstrap --save

4、angular.json 引入bootstrap样式

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/pet-tags-ngrx",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css",
              "node_modules/bootstrap/dist/css/bootstrap.min.css"
            ],
            "scripts": []
          },

5、根组件移入core文件夹

A、在app下添加文件夹core,把app.component的ts、css、html等4个文件移入core文件夹中间。
B、修改app.module.ts中AppComponent的存放位置为

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './core/app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

6、用ng add方式@ngrx所需要的包

ng add @ngrx/store
ng add @ngrx/store-devtools
ng add @ngrx/effects
ng add @ngrx/router-store

添加之后,package.json文件中,dependencies节点为

"dependencies": {
    "@angular/animations": "~11.2.4",
    "@angular/common": "~11.2.4",
    "@angular/compiler": "~11.2.4",
    "@angular/core": "~11.2.4",
    "@angular/forms": "~11.2.4",
    "@angular/platform-browser": "~11.2.4",
    "@angular/platform-browser-dynamic": "~11.2.4",
    "@angular/router": "~11.2.4",
    "@ngrx/effects": "^11.0.1",
    "@ngrx/router-store": "^11.0.1",
    "@ngrx/store": "^11.0.1",
    "@ngrx/store-devtools": "^11.0.1",
    "bootstrap": "^4.6.0",
    "rxjs": "~6.6.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.3"
  },

app.module.ts文件也添加好引用

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './core/app.component';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { EffectsModule } from '@ngrx/effects';
import { StoreRouterConnectingModule } from '@ngrx/router-store';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot({}, {}),
    StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }),
    EffectsModule.forRoot([]),
    StoreRouterConnectingModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

7、运行

ng serve --open
完美,如计划般的完美。

二、构建计数器组件

计划:
1、创建一个带路由的模块,再在模块中构建计算器组件。
2、修改模块和跟模块的路由器,正确导航到计算器组件。

1、新建带路由的模块

ng g m example --routing
在app下增加example文件夹,同时增加example.module.ts(模块文件)、example-routing.module.ts(路由文件)

2、新建计数器组件

ng g c example/containers/counter -m example
A、在example下,创建文件夹containers
B、在containers下,创建文件夹counter
C、在文件夹counter下,创建counter组件的四个文件
D、修改模块文件example.module.ts,增加对counter组件的引用和声明.

3、定义example路由器

修改example-routing.module.ts 模块:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CounterComponent } from './containers/counter/counter.component';

const routes: Routes = [
  { path: '', redirectTo: 'counter', pathMatch: 'full' },
  { path: 'counter', component: CounterComponent },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ExampleRoutingModule { }

引入CounterComponent组件,在routes数组中定义空路由和counter路由.

4、根路由器懒加载example模块及路由

修改app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', redirectTo: 'example', pathMatch: 'full' },
  {path:'example',loadChildren:()=>import('./example/example.module').then(m=>m.ExampleModule)},
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

5、修改根组件的html(app.component.html)

<div class="container-fluid">
  <div class="row">
    <div class="col bg-dark text-white">
      <a class="navbar-brand">ngrx入门</a>
    </div>
  </div>
  <router-outlet></router-outlet>
</div>

6、修改counter组件的html(counter.component.html)

<div class="row">
    <div class="col mt-2">
        <p class="title">计数器: 没有数据请求的ngrx demo</p>
    </div>
</div>
<div class="row">
    <div class="col">
        <div class=" col btn-group m-2">
            <button class="btn btn-primary">加</button>
            <button class="btn btn-danger">减</button>
            <button class="btn btn-secondary">重置</button>
        </div>
    </div>
</div>
<div class="row">
    <div class="col">
        <div>
            <span style="font-size: 18px;font-weight: bold">当前数:18</span>
        </div>
    </div>
</div>

7、运行

完美,如计划般一样的完美。

三、计数器组件普通实现

计划:使用基本的事件绑定机制,实现计数器组件的功能。

1、修改计数器组件的html,按钮绑定事件以及插值输出当前数值

counter.component.html

<div class="row">
    <div class="col mt-2">
        <p class="title">计数器: 没有数据请求的ngrx demo</p>
    </div>
</div>
<div class="row">
    <div class="col">
        <div class=" col btn-group m-2">
            <button class="btn btn-primary" (click)="increment()">加</button>
            <button class="btn btn-danger" (click)="decrement()">减</button>
            <button class="btn btn-secondary" (click)="reset()">重置</button>
        </div>
    </div>
</div>
<div class="row">
    <div class="col">
        <div>
            <span style="font-size: 18px;font-weight: bold">当前数:{{counter$}}</span>
        </div>
    </div>
</div>

2、修改计数器组件的ts,实现数值的增加、减少、重置三个方法

counter.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-counter',
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.css']
})
export class CounterComponent implements OnInit {

  counter$: number = 0;

  constructor() { }

  ngOnInit(): void {
  }

  increment() {
    this.counter$ +=1 ;
  }

  decrement() {
    this.counter$ -=1;
  }

  reset() {
    this.counter$ = 0;
  }

}

3、运行

完美,和计划一样的完美

四、计数器组件ngrx实现

1、构建action

ng g class example/actions/counter.actions

A、example模块的所有action文件都存放在actions文件夹下
B、修改counter.actions.ts为

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

// 为“加-减-重置”三个动作,定义三个字符串常量,用于action中区分.
export const INCREMENT = '[Counter] Increment';  // 这个是唯一的,不能写重复哦
export const DECREMENT = '[Counter] Decrement';
export const RESET = '[Counter] Reset';

//为“加-减-重置”三个动作,分别定义action
export class IncrementAction implements Action {
  readonly type = INCREMENT;
  constructor() { }
}
export class DecrementAction implements Action {
  readonly type = DECREMENT;
  constructor() { }
}
export class ResetAction implements Action {
  readonly type = RESET;
  constructor() { }
}

// 导出定义的Action
export type Actions
  = IncrementAction
  | DecrementAction
  | ResetAction;

2、构建reducer

ng g class example/reducer/counter.reducer

A、example模块的所有reducer文件都存放在reducer文件夹下
B、修改counter.reducer.ts为

import * as counter from '../actions/counter.actions';
import * as counterState from '../state/counter.state';

// 定义reducer 根据action type来处理状态,返回对应数据
export function reducer(state = counterState.initialState, action: counter.Actions): counterState.State {
  switch (action.type) {
    case counter.INCREMENT: // 根据你传的行为的类型,来判断做什么事情
      return {
        counter: state.counter + 1
      };

    case counter.DECREMENT:
      return {
        counter: state.counter - 1
      };

    case counter.RESET:
      return {
      counter: 0
    };

    default:
      return { ...state };
  }
}
// 导出去
export const getCounter = (state: counterState.State) => state.counter;

3、构建index.ts

ng g class example/reducer/index

修改index.ts为

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

import * as fromCounter from './counter.reducer';

export interface State {
  counter: fromCounter.State;
}
export const reducers = {
  counter: fromCounter.reducer,
};

export const getExampleState = createFeatureSelector<State>('example');

// 计数器
export const getCounterState = createSelector(getExampleState, (state: State) => state.counter);
export const getCounterCounter = createSelector(getCounterState, fromCounter.getCounter);

4、在模块中导入reduecer
example.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ExampleRoutingModule } from './example-routing.module';
import { CounterComponent } from './containers/counter/counter.component';

import { StoreModule } from '@ngrx/store';
import { reducers } from './reducer';


@NgModule({
  declarations: [CounterComponent],
  imports: [
    CommonModule,
    ExampleRoutingModule,
    StoreModule.forFeature('example', reducers),  // 挂在在state上
  ]
})
export class ExampleModule { }

5、修改计时器组件的html
counter.component.html

<div class="row">
    <div class="col mt-2">
        <p class="title">计数器: 没有数据请求的ngrx demo</p>
    </div>
</div>
<div class="row">
    <div class="col">
        <div class=" col btn-group m-2">
            <button class="btn btn-primary" (click)="increment()">加</button>
            <button class="btn btn-danger" (click)="decrement()">减</button>
            <button class="btn btn-secondary" (click)="reset()">重置</button>
        </div>
    </div>
</div>
<div class="row">
    <div class="col">
        <div>
            <span style="font-size: 18px;font-weight: bold">当前数:{{counter$ | async}}</span>
        </div>
    </div>
</div>

6、修改计时器组件的ts
counter.component.ts

import { Component, OnInit } from '@angular/core';

import * as fromExample from '../../reducer';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import * as counterAction from '../../actions/counter.actions';
import { OnDestroy } from '@angular/core';

@Component({
  selector: 'app-counter',
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.css']
})
export class CounterComponent implements OnInit , OnDestroy {

  counter$: Observable<number>;
  constructor(private store: Store<fromExample.State>) {
    this.counter$ = store.select(fromExample.getCounterCounter);
  }
  ngOnDestroy(): void {
    throw new Error('Method not implemented.');
  }

  ngOnInit(): void {
  }

  increment() {
    this.store.dispatch(new counterAction.IncrementAction());
  }

  decrement() {
    this.store.dispatch(new counterAction.DecrementAction());
  }

  reset() {
    this.store.dispatch(new counterAction.ResetAction());
  }
}

代码参看:
https://gitee.com/lxhjh2015/ngrx/tree/step1/

 类似资料: