zoukankan      html  css  js  c++  java
  • Angular实现类似vuex状态管理功能、全局数据管理与同步更新

    自定义实现angular中数据的状态管理,如有不妥请指正

    一、先介绍一下rxjs中subject;

    Subject 数据的订阅与分发,结合报刊的发布与订阅进行功能的模拟,subject即是observeable对象也是observer对象,
    subject对于后期没有数据更新时所添加的订阅者是不怎么友好的,因为不跟新数据时订阅者就不在收到返回的数值

        import {subject}from’rxjs’
        const interval$ = interval(1000).pipe(take(10));
        const subject = new Subject();
    
        const observerA = {
          next: value => console.log('Observer A get value: ' + value),
          error: error => console.log('Observer A error: ' + error),
          complete: () => console.log('Observer A complete!'),
        };
    
        const observerB = {
          next: value => console.log('Observer B get value: ' + value),
          error: error => console.log('Observer B error: ' + error),
          complete: () => console.log('Observer B complete!'),
        };
    
        subject.subscribe(observerA); // 添加观察者A
        interval$.subscribe(subject); // 订阅interval$对象
        setTimeout(() => {
          subject.subscribe(observerB); // 添加观察者B
        }, 1000);
    
      import{BehaviorSubject}from’rxjs’;
      //behaviorSubject 是subject的变种,最大的区别就是 behaviorSubject是用于保存最新的数值,而不是单纯的发送事件,会将最后一次发送的值作为当前值保存在内部属性中。
    
        const subject = new BehaviorSubject(0);  //BehaviorSubject小括号0代表的是状态
        const observerA = {
          next: value => console.log('Observer A get value: ' + value),
          error: error => console.log('Observer A error: ' + error),
          complete: () => console.log('Observer A complete!'),
        };
    
        const observerB = {
          next: value => console.log('Observer B get value: ' + value),
          error: error => console.log('Observer B error: ' + error),
          complete: () => console.log('Observer B complete!'),
        };
    
        subject.subscribe(observerA); // 添加观察者A
        // interval$.subscribe(subject); // 订阅interval$对象
        subject.next(1);
        subject.next(2);
        subject.next(3);
        setTimeout(() => {
          subject.subscribe(observerB); // 添加观察者B
        }, 1000);
    
      import {ReplaySubject}from’rxjs’;
      // ReplaySubject 用于重复发送最近几次的值给订阅者
        const subject = new ReplaySubject(2); //ReplaySubject后的2为最后两次发送的数值
        const observerA = {
          next: value => console.log('Observer A get value: ' + value),
          error: error => console.log('Observer A error: ' + error),
          complete: () => console.log('Observer A complete!'),
        };
    
        const observerB = {
          next: value => console.log('Observer B get value: ' + value),
          error: error => console.log('Observer B error: ' + error),
          complete: () => console.log('Observer B complete!'),
        };
    
        subject.subscribe(observerA); // 添加观察者A
        // interval$.subscribe(subject); // 订阅interval$对象
        subject.next(1);
        subject.next(2);
        subject.next(3);
        setTimeout(() => {
          subject.subscribe(observerB); // 添加观察者B
        }, 1000);
    
      import{AsyncSubject}from’rxjs’;
      // AsyncSubject他会在subject完成后才返回一个值
        const subject = new AsyncSubject();
        const observerA = {
          next: value => console.log('Observer A get value: ' + value),
          error: error => console.log('Observer A error: ' + error),
          complete: () => console.log('Observer A complete!'),
        };
    
        const observerB = {
          next: value => console.log('Observer B get value: ' + value),
          error: error => console.log('Observer B error: ' + error),
          complete: () => console.log('Observer B complete!'),
        };
    
        subject.subscribe(observerA); // 添加观察者A
        // interval$.subscribe(subject); // 订阅interval$对象
        subject.next(1);
        subject.next(2);
        subject.next(3);
        subject.complete();
        setTimeout(() => {
          subject.subscribe(observerB); // 添加观察者B
        }, 1000);

      我们要用angular实现类似vuex的全局数据管理就需要用到 BehaviorSubject广播模式

    二、angular服务文件

    在app.module.ts中注册服务文件

    import { SomeSharedService } from '@shared/window-service/window.service';
    providers: [
        ...
        SomeSharedService,
      ],

    TS文件:

    service.module.ts文件

    import { NgModule, ModuleWithProviders } from '@angular/core';
    import { SomeSharedService } from './window.service';
    export { SomeSharedService };
    
    @NgModule()
    export class ServicesModule {
      static forRoot(): ModuleWithProviders {
        return {
          ngModule: ServicesModule,
          providers: [SomeSharedService],
        };
      }
    }

    TS服务文件名:

    window.service.ts文件

    import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs';
    @Injectable()
    export class SomeSharedService {
      public globalVar: BehaviorSubject<any> = new BehaviorSubject({
        dataCount1: 0,
        dataCount2: 0,
        dataCount3: 0,
        dataSum: 0,
      });
      settingKey(key, sumKey) {
        const globalVar = this.globalVar.getValue();
        globalVar[key] -= 1;
        globalVar[sumKey] -= 1;
        this.globalVar.next(globalVar);
      }
    }

    三、全局数据初始化

    在全局公用组件中进行全局数据的初始化,具体怎么用看自己怎么考虑,页面刷新时数据都会重新向后台拿取数据;

    ngOnInit(): void {
         const source = timer(0, 30000);
         const data = source.pipe(
           mergeMap(val => {
             return this.http.get('/admin');
           }),
           distinctUntilChanged(),
         );
         this.distinctSub = data.subscribe(res => {
           this.someSharedService$.globalVar.next(res.data);
          });
      }
     
    ngOnDestroy(): void {
         this.distinctSub.unsubscribe();
       }

    因为业务需要 定时向后台请求一次数据更新,所以简单写了一下 ,如果不需要就只要放一个http请求就行了;

    使用  this.someSharedService$.globalVar.next(res.data); 从全局服务SomeSharedService文件中分发文件;

    四、订阅服务数据

    在需要的页面订阅分发内容,且会保存最后一次的数据;

    import { SomeSharedService } from '@shared/window-service/window.service';
     constructor(
        private someSharedService$: SomeSharedService,
       ) {}
     
     ...
     
     this.someSharedService.globalVar.subscribe(res => {
     
          if (!(this.cdr as ViewRef).destroyed) {
            this.item = res;
            this.cdr.detectChanges();
           }
         });
    // 因为有一些数据渲染的问题 所以需要加一层判断,这就基本实现了从后台拿取数据,在多个页面进行展示;

    五、实现数据修改及同步更新

    import { SomeSharedService } from '@shared/window-service/window.service';
    constructor(
       private someSharedService$: SomeSharedService,
      ) {}
    ...
     
    this.http.get(xxx).subscribe(res => {
            if (res.code !== 200) {
              this.msg.error(res.message);
              return;
            }
      this.someSharedService$.settingKey('dataCount1', 'dataSum');
    })

    当完成数据请求、更新后,修改广播中心的数据,之后同步给接收者一份最新的数据,从而达到广播的的效果;

  • 相关阅读:
    JS jQuery显示隐藏div的几种方法
    PHP 二维数组去重(保留指定键值的同时去除重复的项)
    Java面试题解析(一)
    Java :面向对象
    使用 Spring Framework 时常犯的十大错误
    Spring Boot 面试的十个问题
    《深入理解 Java 内存模型》读书笔记
    Spring Boot 2.0 迁移指南
    MaidSafe区块链项目白皮书解读
    20190712共学问题归纳
  • 原文地址:https://www.cnblogs.com/bomdeyada/p/11718943.html
Copyright © 2011-2022 走看看