当前位置: 首页 > 知识库问答 >
问题:

防止Angular在重新访问管线时构造组件的新实例(管线重用策略)

许彦
2023-03-14

我已将此GitHub存储库中的应用程序用作我的角度路由问题的演示应用程序。

应用程序运行良好。因此,应用程序本身不是我的重点,因为它很简单,但是如果您愿意,您可以完全访问它的代码!

我的问题是,每次在这个angular应用程序中导航时,都会生成相关组件的新实例。

我在代码中做了一些更改来说明这个实例化。我添加了一个简单的计数器,如下所示:

export class ContactListComponent implements OnInit {

  contacts: any[] = [];
  counter = 0; //<--- counter definition

  constructor(private contactService: ContactService) {
    console.log("List Component constructor: #" + ++this.counter); //<--- usage #1
  }

  ngOnInit() {
    console.log("List Component ngInit: #" + ++this.counter); //<--- usage #2
    this.contactService.getContacts().subscribe((data: any[]) => {
      this.contacts = data;
    });
  }
}

如果您查看下图,我所做的每次导航都会生成一个新实例,因此每次计数器都会重置,并且在控制台中,它会显示一次又一次调用了ngInit和构造函数:

我甚至尝试使用以下片段进行导航,得到了相同的结果!:

import { Router, ActivatedRoute } from '@angular/router';
constructor(
        private router: Router
    ) { }

this.router.navigate(['/contacts']);

问题是如何防止这种新的实例化!?

特别是,当我们从第二页返回到第一页时。我正在寻找一种类似于单例的技术,它只会在我们第一次访问某个路由时实例化组件,而在其他时间访问该路由时,我们会得到组件的相同瞬间。

实际上,这个应用程序并不是我正在开发的主要应用程序,我的主要问题是在其他应用程序中,我使用了订阅技术来共享数据,然后当我有一个组件的多个实例时,不同实例中的以下代码将被激发,结果不符合预期。为什么?因为如果(this.agreeTerms)在不同的实例中同时具有不同的值!

navNext(next) {
        this.next = next;
        if (this.next === true && this.router.url.startsWith('/') && this.router.url.endsWith('/')) {            
            this.data.unsetNext();
            if (this.agreeTerms) { //<-----
                this.router.navigate(['/form']);
            } else {
                this.error = 'Please accept the terms and conditions';
                this.scrollBottom();
            }
        }
    }

共有1个答案

费星晖
2023-03-14

与您对@anatoli的评论相关,使用RouteReuseStrategy将解决此问题。例如,请参阅此处。首先我们必须创建一个服务类:

RouterUseService。ts

import {
    RouteReuseStrategy,
    ActivatedRouteSnapshot,
    DetachedRouteHandle,
    RouterModule,
    Routes,
    UrlSegment
} from '@angular/router';
export class RouteReuseService implements RouteReuseStrategy {
    private handlers: { [key: string]: DetachedRouteHandle } = {};
    shouldDetach(route: ActivatedRouteSnapshot): boolean {
        if (!route.routeConfig || route.routeConfig.loadChildren) {
            return false;
        }
        let shouldReuse = false;
        console.log('checking if this route should be re used or not’, route');
        if (route.routeConfig.data) {
            route.routeConfig.data.reuse ? shouldReuse = true : shouldReuse = false;
        }
        return shouldReuse;
    }
    store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): void {
        console.log('storing handler');
        if (handler) {
            this.handlers[this.getUrl(route)] = handler;
        }
    }
    shouldAttach(route: ActivatedRouteSnapshot): boolean {
        console.log('checking if it should be re attached');
        return !!this.handlers[this.getUrl(route)];
    }
    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
        if (!route.routeConfig || route.routeConfig.loadChildren) {
            return null;
        };
        return this.handlers[this.getUrl(route)];
    }
    shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
        let reUseUrl = false;
        if (future.routeConfig) {
            if (future.routeConfig.data) {
                reUseUrl = future.routeConfig.data.reuse;
            }
        }
        const defaultReuse = (future.routeConfig === current.routeConfig);
        return reUseUrl || defaultReuse;
    }
    getUrl(route: ActivatedRouteSnapshot): string {
        if (route.routeConfig) {
            const url = route.routeConfig.path;
            console.log('returning url', url);
            return url;
        }
    }
}

下一步,我们必须对app.module.ts做一些改变:

providers: [{provide: RouteReuseStrategy, useClass: RouteReuseService}],
  bootstrap: [AppComponent]

在最后一步中,我们必须将组件的“重用”设置为true,我们希望在应用程序中重用它(app-routing.modules.ts)。例如,这里我们想要重用DetailComponent:

const routes: Routes = [{ path: '', component: HomeComponent },
{
  path: 'detail', component: DetailComponent, data: {
    reuse: true
  }
}, { path: 'item', component: ItemComponent }];
 类似资料:
  • 问题内容: 想象一下以下课程: 我想重新启动线程以防万一。这不起作用。因为线程只能启动一次。第一个问题。为什么是这样? 据我所知,我必须重新创建的每个实例并调用以再次启动线程。如果是s,这不是很实际。我必须读取旧值的当前值,创建一个新值,并使用旧值在新对象中设置参数。第二个问题:这可以用更聪明,更轻松的方式完成吗? 问题答案: 之所以以这种方式实现threading.Thread,是为了保持线程对

  • 我正在学习React钩子,这意味着我将不得不从类转移到函数组件。以前,在类中,我可以拥有与状态无关的类变量,我可以在不重新呈现组件的情况下更新这些变量。现在我试图用钩子重新创建一个组件作为函数组件,我遇到了这样一个问题:我不能(就我所知)为该函数创建变量,因此存储数据的唯一方法是通过钩子。然而,这意味着每当该状态更新时,我的组件将重新呈现。 我已经在下面的示例中说明了这一点,我试图将类组件重新创建

  • 我正在开发一个应用程序播放器。请看下面的图片: 进度条必须显示当前时间,但每次勾选,我的组件都会重新呈现所有内容。这导致我的应用程序运行缓慢。 这是我的代码:

  • 我从这里修改了以下组件定义,如下所示。但是,与示例不同的是,每次在组件上移动鼠标时,组件都会重新呈现。 重新渲染非常引人注目: 有人知道为什么会这样吗?

  • 我对react还比较陌生,我一直在分解一个web应用程序,并用react组件替换部分。我现在正在开发一个组件,其中包含我创建的几个不同组件。 在新组件中,我在componentDidMount函数中进行API调用,并创建子组件。乍一看,一切看起来都很完美,但当我们在其中一个子组件中进行状态更改,然后在父组件中进行更改时,子组件将其状态重置为更改之前的状态。 我知道发生了什么,州政府没有被传递给家长

  • 问题内容: 旋转屏幕时,WebView会重新加载整个页面。我无法使用此功能,因为我的某些内容包含动态/随机材料。当前,屏幕旋转时会从loadUrl()方法重新加载原始URL。 知道我的代码有什么问题吗? MainActivity.java AndroidManifest.xml 问题答案: 我认为主要问题是您调用了web.loadUrl(webURL); 当saveInstanceState!=