美文网首页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框架中的父子组件通信传递异步的数据接收值异常的问题

    父组件传递给子组件的值为async data异步数据,子组件接收的过程中可能就会出现问题,子组件接收不到父组件传递...

  • Vue常见问题

    1. 父子组件间通信 父组件传递数据给子组件(通过props属性来实现) 子组件通过props来接收数据 子组件与...

  • Vue如何实现组件通信?

    Vue组件通信的三种情况: 父子通信 爷孙通信 兄弟通信 父子通信:父组件使用Prop向子组件传递数据,子组件通过...

  • 初识Angular2的组件通信

    Angular2中免不了进行父子组件的通信,现在就稍微的了解一下父组件怎么给子组件传值,首先,通过Angular-...

  • angular父子组件之间的传值

    父子组件的传值,是mvvm框架中必然绕不过去的话题,下面列举在angular中父子组件传值的各种方式。 一、通过输...

  • Vue入门系列(五)组件通信

    组件内通信主要分为两种:父子组件通信和子组件之间通信。 1.父子组件通信 父组件通过props属性向子组件传递数据...

  • Vue 组件详解之组件通信

    组件中的关系可分为父子组件通信、兄弟组件通信和跨级组件通信。 一、自定义事件 ---- 子组件给父组件传递数据 我...

  • Vue的组件通信

    Vue的父子通信问题 参考文档 : Vue 组件组合 使用 props传递数据 用v-on 绑定事件 原理: 父子...

  • Vue 组件 / 通信

    子组件=》父组件 vue的组件之间的通信类似angular的父子层级之间通信,父组件获取子组件数据步骤大概如下: ...

  • VUE组件通信的十种姿势

    父子组件通信 1、父子组件通过prop传递数据 父组件可以将一条数据传递给子组件,这条数据可以是动态的,父组件的数...

网友评论

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

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