【问题标题】:Angular 7: Service instance working incorrectlyAngular 7:服务实例工作不正确
【发布时间】:2020-09-02 00:49:51
【问题描述】:

我的应用中有两个组件——“过滤器”和“主页”。这两个组件是 app 组件的子组件。

我有一个下面的对象,我想通过服务从过滤器组件传递到主组件。由于我希望这些数据在过滤器组件中发生更改时在主组件中更新,因此我在服务中使用 BehaviorSubject。

模型:filter-response.model.ts

export interface FilterResponse{
    filter:string;
    filterlist:string[];
}

filter.component.ts

export class FilterComponent implements OnInit {
    filterMainList:FilterResponse[]=[
        {
            "filter": "abc",
            "filterlist": ["a","b","c"]
        },
        {
            "filter": "def",
            "filterlist":["d","e","f"]
        },
        {
            "filter": "ghi",
            "filterlist": ["g","h","i"]
        }
    ];
    constructor(private filterService:FilterService,) {
        this.filterService.setFilterConditions(this.filterMainList);
    }
    ngOnInit() {
    }
}

在 home 组件中,我收到了数据,我想对其进行一些更改。

home.component.ts

export class HomeComponent implements OnInit {
  constructor(private filterService:FilterService) {
    this.filterService.getFilterConditions().subscribe((data)=>{
      let tc:FilterResponse[]=data
      for(let f in tc){
        tc[f].filterlist=['changes'];//this is where I make the changes
      }
    });
   }
  ngOnInit() {
  }
}

我有一个具有行为主题的过滤服务。这就是我感到困惑的地方。我在 next() 之前将数据记录在服务中,而我实际获得的数据是我在 home 组件中更改的,这意味着我对 home 组件中的数据实例所做的更改也会影响(更改)服务中的数据。

filter.service.ts

@Injectable({
    providedIn:'root'
})
export class FilterService{
    private filterConditions = new BehaviorSubject<FilterResponse[]>(null);
    constructor(){}
    setFilterConditions(filterList:FilterResponse[]){
        console.log(filterList);//data changes incorrectly
        this.filterConditions.next(filterList);
    }
    getFilterConditions():Observable<FilterResponse[]>{
        return this.filterConditions.asObservable();        
    }
}

我的控制台日志:

实际上应该是我刚刚在过滤器组件中传递的数据。但它显示了我在 home 组件中修改的数据。

最后是 app.component.ts,如果有帮助的话

app.component.ts

<app-filter></app-filter>
<app-home></app-home>

我想提请您注意的另一件事是。我试图在 stackblitz 中重新创建场景。但奇怪的是它在那里工作得很好。

https://stackblitz.com/edit/angular-ivy-9th5pj

请解释我的项目中缺少什么。或者这是服务将以角度工作的实际方式。

【问题讨论】:

  • 你的真实代码中可能有一些不同的东西。您可能以某种方式多次致电this.filterService.setFilterConditions。您的控制台中真的只有 1 个日志输出吗?
  • 是的。我在控制台中只有一个日志。如果我不止一次调用 this.filterService.setFilterConditions,我至少会有不止一个日志。
  • 在没有源代码的情况下很难解释为什么会发生这种情况...您是否尝试设置断点来理解流程?

标签: angular typescript angular7 angular-services behaviorsubject


【解决方案1】:

我误解了您的问题:我认为您的问题是为什么 console.log 输出显示修改后的数组,同时放置在修改之前

就像khush's answer 中解释的那样,非原始类型通过引用传递:JS 不会将数组的副本传递给函数/方法,而是传递数组本身。这就是通过 next 传递并在您的 HomeComponent 中修改的相同数组实例 (filterMainList)。

现在,您在修改数据之前有console.log(filterList),但日志输出仍然显示更改。这是因为当您在浏览器的控制台中单击Array(3) 时,调试器此时会评估变量的值,此时该变量已被修改。

这在您的 stackblitz 示例中不可见,因为您没有记录数组,而是 JSON.stringify(arr)。在这种情况下,您无需在控制台中扩展该值,该值已显示为字符串并且不会被重新计算。 如果我们只记录变量,stackblitz demo 将重现相同的“问题”

如果这种行为不是你想要的,你可以按照 khush 的建议克隆传递的数据;来自发送它的组件,或者在调用next之前直接在您的服务中,如果您的代码中有多次调用setFilterConditions,您只需执行一次

【讨论】:

    【解决方案2】:

    在您的服务文件中进行此更改

     setFilterConditions(filterList:FilterResponse[]){
        this.filterConditions.next(JSON.parse(JSON.stringify(filterList)));
    }
    

    这将克隆你的数组。还有许多其他方法可以在 JS 中克隆对象/数组 Different ways to Clone object in JS

    原因

    在 TS 中,当将对象作为函数参数传递时,您传递的是对该对象的引用。因此,当修改传递给函数的对象时,您正在修改原始对象。

    类似地,在HomeComponent的订阅函数中接收到的数组/对象是通过引用接收的。因此,HomeComponent 中的值变化也会在服务中受到影响。

    【讨论】:

    • 是的,这将解决问题,但我认为 OP 想了解为什么会出现此错误
    • 这不是错误。这就是所有非原始值在 TS 中传递的方式。
    • 是的。正如大卫所说,我认为这是错误。
    • 谢谢库什。因此,每当我使用服务在组件之间传递对象的实例时,我实际上应该传递对象的克隆而不是对象本身的实例。希望我明白了。
    • 是的,如果您要进行任何更改或操作订阅的数据,那么您必须克隆数据。
    【解决方案3】:

    我将扩展 Khush 的答案。因此,如果创建深层副本没有任何效果,那么您可以从 loadash 中使用 cloneDeep 函数。请在最坏的情况下使用此选项(修补程序问题)。 由于浅拷贝而出现此问题。 因此,当您在每种情况下返回数组时,您不是返回一个新数组,而是返回数组的地址。因此,无论阵列发生什么变化,您的原始阵列都会发生变化。当您使用 JSON.stringigy 或 deepClone 函数时,您会在内部创建具有不同地址的数组副本

    setFilterConditions(filterList:FilterResponse[]){
        this.filterConditions.next(cloneDeep(filterList));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-06
      • 1970-01-01
      • 2018-10-19
      • 2017-03-14
      • 1970-01-01
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      相关资源
      最近更新 更多