Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.1k views
in Technique[技术] by (71.8m points)

Angular onPush检测机制相关问题

问题的产生: 搜索学习 Angular onPush 相关知识,还原一篇文章中的例子,结果没有出现文章中提到的问题.

onPush检测机制的执行条件是只有当传入的值有变化.简单类型是值变化,而复杂类型是引用变化,才会执行组件内部的state更新然后更新视图。经常使用 xxx.slice(),这个 xxx 应该是一种什么数据结构 ?

文章中代码如下:

add (): void {
  this.employeeList.unshift(new Employee('haha', 15))
  this.employeeList = this.employeeList.slice()
}

我还原的this.employeeList结构如下:

  employeeList: Employee[] = [
    {
        name: "软件开发工程师",
        rate: 4,
    },
    {
      name: "业务设计师",
      rate: 5,
    },

  ]

也就是说,我还原的代码,没有使用 this.employeeList.slice() 这句,数据就变化了.

原文章: https://zhuanlan.zhihu.com/p/...

恢复文章的例子:
1.Employee.ts

export class Employee {
    name: string;
    rate: number;
    constructor(name, rate) {
        this.name = name;
        this.rate = rate;
    }
}

2.app.component.ts

export class AppComponent {
  title = 'hello-angular';
  departmentName = 'Front End'
  employeeList: Employee[] = [
    {
        name: "PPQA",
        rate: 3,
    },
    {
        name: "软件开发工程师",
        rate: 4,
    },
    {
      name: "业务设计师",
      rate: 5,
    },
    {
      name: "UI设计师",
      rate: 6,
    },
    {
      name: "销售代表",
      rate: 7,
    },
  ]

  add (): void {
    console.log(123)
    this.employeeList.push(new Employee('中国航天科工工程总院客户联络代表', Math.floor((Math.random()*10)+30)))
    this.employeeList = this.employeeList.slice() // 此行删除,数据也会更新
  }

  addEnter (name: string): void {
    console.log(456)
    this.employeeList.unshift(new Employee(name, Math.floor((Math.random()*10)+30)))
    this.employeeList = this.employeeList.slice()
  }

  removeThis (employee: Employee): void {
    console.log(employee)
    this.employeeList = this.employeeList.filter((item) => {
      return !employee.name.includes(item.name)
    });

  }
}

3.app.component.html

<button (click)="add()">add</button>
<app-employee-list [departmentName]='departmentName' [employeeList]="employeeList" (add)="addEnter($event)" (remove)="removeThis($event)"></app-employee-list>

4.employee-list.component.ts

import { Component, Input, Output, EventEmitter } from "@angular/core";
import { Employee } from './Employee';

const fibonacci = (num: number): number => {
  if (num === 1 || num === 2) {
    return 1;
  }
  return fibonacci(num - 1) + fibonacci(num - 2);
}

@Component({
  selector: 'employee-list',
  templateUrl: './Employee.component.html',
  styleUrls: ['./Employee.component.scss']
})
export class EmployeeListComponent {
  @Input() departmentName: string
  @Input() employeeList: Employee[]

  @Output() remove = new EventEmitter<Employee>()
  @Output() add = new EventEmitter<string>()

  name: string

  handleKey (event: any): void {
    if (event.keyCode === 13) {
      this.add.emit(this.name)
      this.name = ''
    }
  }

  handleRemove (employee: Employee): void {
    this.remove.emit(employee)
  }

  calculate (num: number) {
    return fibonacci(num)
  }
}

5.employee-list.component.html

<div class="employee-container">
  <h1>{{ departmentName }}</h1>
  <p>
    <label for="employee"></label>
    <input type="text" id="employee" placeholder="please input a employee name" [(ngModel)]="name" (keydown)="handleKey($event)" />
  </p>
  <ul>
    <li *ngFor="let employee of employeeList">
      <span>{{ employee.name }}</span>
      <span class="rate">{{ calculate(employee.rate) }}</span>
      <button (click)="handleRemove(employee)">delete</button>
    </li>
  </ul> 
</div>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

xxx是个数组。
slice()是数组的一个方法. xxx = xxx.slice(); 作用是:复制xxx数组,并使用复制后的值来替换xxx。
此时xxx由原数组变更为与原数组完全相同的新数组。但由于是新数组的原因,所以xxx的引用值变更了,此时则会触发检测条件。从而使得重新对视图进行渲染。

看你发了不少关于angular的文章,个人建议还是多实践,只有自己动手的时候碰到问题了,解决问题的方法才会过目不忘。你现在看似学的快,但实际上大脑可能已经忘却了很多以前学过的东西。

感觉没有必要非得找个不更新的例子试。angular的检测机制,在大多数情况下都是可以感知到更新的(哪怕你是数组)。

可以试试如下代码:

 addEnter (name: string): void {
    console.log(456);
    setTimeout(() => {
            this.employeeList.unshift(new Employee(name, Math.floor((Math.random()*10)+1)))
    }, 2000);
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...