美文网首页Angular框架专题
Angular框架中的父子组件通信传递异步的数据接收值异常的问题

Angular框架中的父子组件通信传递异步的数据接收值异常的问题

作者: 听书先生 | 来源:发表于2021-12-08 22:59 被阅读0次

    父组件传递给子组件的值为async data异步数据,子组件接收的过程中可能就会出现问题,子组件接收不到父组件传递过来的值,此时视图也无法进行渲染。

    • 子组件message组件:
    import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
    import { Post, GroupPosts } from '../post.interface';
    
    // 定义接口
    export interface Post {
        title: string;
        category: string;
    }
    export interface GroupPosts {
        category: string;
        posts: Post[];
    }
    @Component({
        selector: 'exe-message',
        template: `
        <div class="list-group">
            <div *ngFor="let group of groupPosts;" class="list-group-item">
                <h4>{{ group.category }}</h4>
                <ul>
                    <li *ngFor="let post of group.posts">
                        {{ post.title }}
                    </li>
                </ul>
            <div>
        </div>
        `
    })
    export class ExeMessageComponent implements OnInit {
    
        _data = [];
    
        @Input()
        set data(value: any) {
            this._data = value;
        }
    
        get data() {
            return this._data;
        }
    
        groupPosts: GroupPosts[] = [];
    
        ngOnInit() {
          this.groupPosts = this.groupByCategory(this.data);
        }
    
        ngOnChanges(changes: SimpleChanges) {
    
        }
    
        groupByCategory(data: Post[]): GroupPosts[] {
            if (!data) return [];
            // 去重处理
            const categories = new Set(data.map(x => x.category));
            // 转为二维数组
            const result = Array.from(categories).map(x => ({
                category: x,
                posts: data.filter(post => post.category === x)
            }));
            return result;
        }
    }
    
    • 父组件User组件部分:
    import { Component, OnInit, Input, SimpleChanges } from '@angular/core';
    import { Observable, Observer } from 'rxjs';
    
    // 定义接口
    export interface Post {
        title: string;
        category: string;
    }
    export interface GroupPosts {
        category: string;
        posts: Post[];
    }
    @Component({
        selector: 'exe-bloggers',
        template: `
            <h1>{{ blogger }}</h1>
            <div>
                <exe-message [data]="posts"></exe-message >
            </div>
        `
    })
    export class KeysComponent implements OnInit {
    
        blogger = 'catalogue';
        posts: Post[] = [];
    
        ngOnInit() {
            this.getPosts().subscribe(posts => this.posts = posts);
        }
    
        getPosts(): Observable<Post[]> {
            return Observable.create((observer: Observer<Post[]>) => {
                setTimeout(() => {
                    const posts = [
                        { "title": "containing a catalogue", "category": "react" },
                        { "title": "and an agreement.", "category": "vue" },
                        { "title": "show that we have sent", "category": "react" },
                        { "title": "gives a full description of each product", "category": "angular" },
                        { "title": "Topshop has coined an online category ", "category": "react" },
                        { "title": "The catalogue gives a full description", "category": "vue" }
                    ];
                    observer.next(posts);
                }, 2000);
            })
        }
    }
    
    image.png

    根据结果来看,子组件并未接收到,获取的值是一个空数组。

    2、解决方案
    • 使用ngOnChanges() :
      当数据绑定输入属性的值发生变化的时候,Angular内部将会主动调用 ngOnChanges() 方法。它会获得一个 SimpleChanges 对象,包含绑定属性的新值和旧值,因此利用 ngOnChanges() 钩子函数,执行子组件的数据初始化的操作。
    import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
    import { Post, GroupPosts } from '../post.interface';
    
    // 定义接口
    export interface Post {
        title: string;
        category: string;
    }
    export interface GroupPosts {
        category: string;
        posts: Post[];
    }
    @Component({
        selector: 'exe-message',
        template: `
        <div class="list-group">
            <div *ngFor="let group of groupPosts;" class="list-group-item">
                <h4>{{ group.category }}</h4>
                <ul>
                    <li *ngFor="let post of group.posts">
                        {{ post.title }}
                    </li>
                </ul>
            <div>
        </div>
        `
    })
    export class ExeMessageComponent implements OnInit {
    
        _data = [];
    
        @Input()
        set data(value: any) {
            this._data = value;
        }
    
        get data() {
            return this._data;
        }
    
        groupPosts: GroupPosts[] = [];
    
        ngOnInit() {
          this.groupPosts = this.groupByCategory(this.data);
        }
    
        ngOnChanges(changes: SimpleChanges) {
          console.log(changes)
          if (changes['data']) {
             this.groupPosts = this.groupByCategory(this.data);
          }
        }
    
        groupByCategory(data: Post[]): GroupPosts[] {
            if (!data) return [];
            // 去重处理
            const categories = new Set(data.map(x => x.category));
            // 转为二维数组
            const result = Array.from(categories).map(x => ({
                category: x,
                posts: data.filter(post => post.category === x)
            }));
            return result;
        }
    }
    
    image.png image.png
    • 使用RxJS中的BehaviorSubject:
      利用 RxJS 中 BehaviorSubject 来监测变化。需要注意的是,在使用 Observable时,在不使用的时候,需要在ngOnDestroy钩子在去取消订阅,以避免出现内存泄露的问题。
    import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
    import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
    import { Post, GroupPosts } from '../post.interface';
    
    // 定义接口
    export interface Post {
        title: string;
        category: string;
    }
    export interface GroupPosts {
        category: string;
        posts: Post[];
    }
    @Component({
        selector: 'exe-message',
        template: `
        <div class="list-group">
            <div *ngFor="let group of groupPosts;" class="list-group-item">
                <h4>{{ group.category }}</h4>
                <ul>
                    <li *ngFor="let post of group.posts">
                        {{ post.title }}
                    </li>
                </ul>
            <div>
        </div>
        `
    })
    export class ExeMessageComponent implements OnInit {
    
      private _data$ = new BehaviorSubject<Post[]>([]);
    
      @Input()
      set data(value: Post[]) {
        this._data$.next(value);
      }
    
      get data(): Post[] {
        return this._data$.getValue();
      }
    
    
        groupPosts: GroupPosts[] = [];
    
        ngOnInit() {
          this._data$.subscribe((x: any) => {
            this.groupPosts = this.groupByCategory(this.data);
          });
        }
        
        ngOnDestroy(): void {
          // 如果数据不断的变化需要取消订阅
          this._data$.unsubscribe();
        }
    
        ngOnChanges(changes: SimpleChanges) { }
    
        groupByCategory(data: Post[]): GroupPosts[] {
            if (!data) return [];
            // 去重处理
            const categories = new Set(data.map(x => x.category));
            // 转为二维数组
            const result = Array.from(categories).map(x => ({
                category: x,
                posts: data.filter(post => post.category === x)
            }));
            return result;
        }
    }
    
    image.png
    • 使用Observable:
      我们也可以尝试着使用Observable对象,将输入的属性的类型设置为Observable即可。
      子组件message:
    import { Observable, Observer } from 'rxjs';
    
      ...
     @Input() data: Observable<Post[]>; // 输入属性的类型是Observable
    

    父组件User组件:

    import { Observable, Observer } from 'rxjs';
    
     ...
    posts: Observable<Post[]>;
    

    如果想在模板中直接使用的话,可以使用AsyncPipe
    在实际的开发场景中,需要参考业务层的应用方式,如果数据源只产生一次或者很少的次数的变化,那么可以直接考虑使用*ngIf指令,即当父组件异步数据获取到的时候才进行子组件的加载。如果是持续不断的改变,那么需要使用以上的方法去解决异步导致数据源无法获取的问题。

    相关文章

      网友评论

        本文标题:Angular框架中的父子组件通信传递异步的数据接收值异常的问题

        本文链接:https://www.haomeiwen.com/subject/ayhxfrtx.html