【问题标题】:Router Navigate does not call ngOnInit when same page同一页面时,Router Navigate 不调用 ngOnInit
【发布时间】:2017-05-31 09:47:03
【问题描述】:

我在同一页面上使用一些查询字符串参数调用router.navigate。在这种情况下,ngOnInit() 不会调用。是默认还是我需要添加什么?

【问题讨论】:

    标签: angular navigateurl ngoninit


    【解决方案1】:

    您可以注入ActivatedRoute并订阅params

    constructor(route:ActivatedRoute) {
      route.params.subscribe(val => {
        // put the code from `ngOnInit` here
      });
    }
    

    路由器只有在导航到不同的路由时才会销毁并重新创建组件。当只更新路由参数或查询参数但路由相同时,组件不会被销毁和重新创建。

    强制重新创建组件的另一种方法是使用自定义重用策略。另见Angular2 router 2.0.0 not reloading components when same url loaded with different parameters?(似乎还没有太多可用的信息如何实现它)

    【讨论】:

    • 此订阅不起作用,它只会在初始化时触发
    • @OsandaWedamulla 那是特定于您的代码的。没有更多细节很难说
    • 您不需要取消订阅还是自动完成?
    • @rain01 根据经验,当您明确订阅时,您应该在 cpde 中明确取消订阅。如果您的根组件中有上述代码,那么取消订阅是多余的,因为根组件的生命周期通常与整个 Angular 应用程序的生命周期相同。
    • 此解决方案与stackoverflow.com/a/47827668/5284473(或全局设置 onSameUrlNavigation)结合使用。
    【解决方案2】:

    NgOnInit 将在创建实例时调用一次。对于同一个实例,NgOnInit 不会再次被调用。为了调用它,必须销毁创建的实例。

    【讨论】:

      【解决方案3】:

      考虑将您在 ngOnInit 中的代码移动到 ngAfterViewInit 中。 后者似乎是在路由器导航中调用的,在这种情况下应该对您有所帮助。

      【讨论】:

      • 这不会真的发生
      【解决方案4】:

      你可以在路由器上调整reuseStrategy。

      constructor(private router: Router) {
          // override the route reuse strategy
          this.router.routeReuseStrategy.shouldReuseRoute = function() {
              return false;
          };
      }
      

      【讨论】:

      • 这将启动页面上每个组件的 ngInit。
      • 好吧,@Pascal,你强迫我登录 SO 只是为了给你的答案投票。我要补充一点,在 Angular 6 中,您还必须将 onSameUrlNavigation: 'reload' 添加到配置对象中,如下所示:RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'})。不过,不能代表任何其他 Angular 版本。
      • @Hildy,我不得不这样做:) 谢谢@Pascal!如果你更喜欢 lambda,你可以这样做 this.router.routeReuseStrategy.shouldReuseRoute = () => false;
      • @Swaprks 我创建了一个 routing.module.ts 并将代码放置为这个构造函数
      • @Swaprks .. 我有一个类似的问题,想试试你上面的答案。但作为这个领域的初学者,它并没有告诉我太多。我应该在代码中的哪个位置放置这段代码?我是否应该更改代码 sn-p 中的任何内容(例如 'function()' )?如果您创建了一个名为 routing.module.ts 的新文件,那么它应该如何与其他文件交互?还有一个名为 app-routing.module.ts 的文件是自动创建的。
      【解决方案5】:

      这个问题很可能是因为您没有使用 ngOnDestroy 终止订阅。以下是如何完成。

      1. 引入以下 rxjs 订阅导入。 import { Subscription } from 'rxjs/Subscription';

      2. 将 OnDestory 添加到您的 Angular 核心导入中。 import { Component, OnDestroy, OnInit } from '@angular/core';

      3. 将 OnDestory 添加到您的导出类。 export class DisplayComponent implements OnInit, OnDestroy {

      4. 在您的导出类下为组件上的每个订阅创建一个值为 Subscription from rxjs 的对象属性。 myVariable: Subscription;

      5. 将您的订阅值设置为 MyVariable: Subscriptions。 this.myVariable = this.rmanagerService.getRPDoc(books[i].books.id).subscribe(value => {});

      6. 然后在 ngOninit 正下方放置 ngOnDestory() 生命周期钩子,并在您的取消订阅语句中放入您的订阅。如果您有多个,请添加更多 ngOnDestroy() { this.myVariable.unsubscribe(); }

      【讨论】:

      • 我自己也一直在输入ngOnDestory 而不是ngOnDestroy ;-)
      【解决方案6】:

      您可能需要重新加载页面吗?这是我的解决方案:我已经更改了 @NgModule(在我的情况下是 app-routing.module.ts 文件):

      @NgModule({
        imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})] })
      

      【讨论】:

      • 这里的“路线”是什么。
      • @DhwanilPatel 您的 Angular 应用程序路由。例如“const routes: Routes = [ { path: 'crisis-center', component: CrisisListComponent }, { path: 'heroes', component: HeroListComponent }, ]”angular.io/guide/router#register-router-and-routes
      【解决方案7】:

      当你想在同一页面上进行路由导航并想调用 ngOnInit() 时,你会这样做,例如,

      this.router.navigate(['category/list', category]) .then(() => window.location.reload());

      【讨论】:

        【解决方案8】:

        为 routes 数组中的同一个组件创建不同的路径。

        常量路线:路线= [{ 路径:“应用程序”, 组件:我的组件 }, { 路径:“应用程序重新加载”, 组件:我的组件 }];

        如果当前 URL 是“app” 然后使用“app-reload”导航,反之亦然。

        【讨论】:

          【解决方案9】:

          这里是此页面上最好的想法的集合,其中包含更多信息

          解决方案 1 - 使用参数订阅:

          教程:https://angular-2-training-book.rangle.io/routing/routeparams#reading-route-parameters

          文档:https://angular.io/api/router/ActivatedRoute#params

          在每个使用参数变量的路由组件中包括以下内容:

          import { Component, OnInit, OnDestroy } from '@angular/core';
          import { ActivatedRoute } from '@angular/router';
          import { Subscription } from 'rxjs';
          
          // ...
          
          @Component({
              // ...
          })
          export class MyComponent implements OnInit, OnDestroy {
              paramsSub: Subscription;
          
              // ...
          
              constructor(activeRoute: ActivatedRoute) {
          
              }
          
              public ngOnInit(): void {
                  // ...
                  this.paramsSub = this.activeRoute.params.subscribe(val => {
                      // Handle param values here
                  });
          
                  // ...
              }
          
              // ...
          
              public ngOnDestroy(): void {
                  // Prevent memory leaks
                  this.paramsSub.unsubscribe();
              }
          }
          

          此代码的一些常见问题是订阅是异步的,处理起来可能比较棘手。此外,您不能忘记取消订阅 ngOnDestroy,否则可能会发生坏事。

          好消息是,这是处理此问题的文档最多且最常用的方法。这样做还可以提高性能,因为您可以重复使用模板,而不是每次访问页面时都销毁和重新创建。

          解决方案 2 - shouldReuseRoute / onSameUrlNavigation:

          文档:https://angular.io/api/router/ExtraOptions#onSameUrlNavigation

          文档:https://angular.io/api/router/RouteReuseStrategy#shouldReuseRoute

          文档:https://angular.io/api/router/ActivatedRouteSnapshot#params

          查找RouterModule.forRoot 在您的项目中的位置(通常在 app-routing.module.ts 或 app.module.ts 中找到):

          const routes: Routes = [
             // ...
          ];
          
          // ...
          
          @NgModule({
              imports: [RouterModule.forRoot(routes, {
                  onSameUrlNavigation: 'reload'
              })],
              exports: [RouterModule]
          })
          

          然后在 AppComponent 中添加以下内容:

          import { Component, OnInit} from '@angular/core';
          import { Router } from '@angular/router';
          
          // ...
          @Component({
              // ...
          })
          export class AppComponent implements OnInit {
              constructor(private router: Router) {
              }
          
              ngOnInit() {
                  // Allows for ngOnInit to be called on routing to the same routing Component since we will never reuse a route
                  this.router.routeReuseStrategy.shouldReuseRoute = function() {
                      return false;
                  };
          
                  // ...
              }
          
              // ...
          }
          
          

          最后,在您的路由组件中,您现在可以像这样处理参数变量:

          import { Component, OnInit } from '@angular/core';
          import { ActivatedRoute } from '@angular/router';
          
          // ...
          
          @Component({
              // ...
          })
          export class MyComponent implements OnInit {
              // ...
          
              constructor(activeRoute: ActivatedRoute) {
          
              }
          
              public ngOnInit(): void {
                  // Handle params
                  const params = +this.activeRoute.snapshot.params;
          
                  // ...
              }
          
              // ...
          }
          

          此解决方案的常见问题是它并不常见。此外,您正在更改 Angular 框架的默认行为,因此您可能会遇到人们通常不会遇到的问题。

          好处是您的所有代码都是同步的并且更易于理解。

          【讨论】:

            【解决方案10】:

            角度 9

            我已经使用了以下方法并且它有效。

            onButtonClick() {
                this.router.routeReuseStrategy.shouldReuseRoute = function () {
                    return false;
                }
                this.router.onSameUrlNavigation = 'reload';
                this.router.navigate('/myroute', { queryParams: { index: 1 } });
            }
            

            【讨论】:

            • 另外,上面也用lambda代替,this.router.routeReuseStrategy.shouldReuseRoute = () => false;
            • 在 Angular 8 中工作。
            • 这会改变整个应用程序的路由器行为,还是只为这个特定的navigate()触发一次?
            • 在 Angular 9 中工作。
            • @Halfist 我观察到的是在设置了shouldReuseRoute之后,是为整个app设置的。我通过使用第 1 页上的 console.log(this.router.routeReuseStrategy 进行了检查,在第 2 页上将策略设置为该功能,然后导航回第 1 页。在初始加载时第 1 页报告没有功能,但在导航到第 2 页后并且返回该功能仍然存在。如果您只想在 1 个组件中使用它,也许在 NgOnDestroy 中重新设置策略?
            【解决方案11】:

            关于你的导航方式,

            this.router.routeReuseStrategy.shouldReuseRoute = () => false;
            this.router.onSameUrlNavigation = 'reload';
            this.router.navigate(['/document'], {queryParams: {"search": currentSearch}});
            

            【讨论】:

            • 这会破坏导航模型的其余部分
            【解决方案12】:

            我遇到了同样的问题,另外我收到了警告:

            did you forget to call `ngZone.run()`
            

            This网站提供了最佳解决方案:

            import { Router } from '@angular/router';
            import { NgZone } from '@angular/core';
            
            ...
            
              constructor(
                private ngZone:NgZone,
                private _router: Router
              ){ }
            
              redirect(to) {
                // call with ngZone, so that ngOnOnit of component is called
                this.ngZone.run(()=>this._router.navigate([to]));
              }
            

            【讨论】:

            • 关于这个,我想知道当你用新路由刷新页面时如何处理这个问题。在这种情况下,NgZone 警告仍然存在。
            【解决方案13】:

            这是Router Navigate在同一页面不调用ngOnInit函数的最佳解决方案

            // override the route reuse strategy
            this.router.routeReuseStrategy.shouldReuseRoute = function() {
                return false;
            };
            

            【讨论】:

              【解决方案14】:
              // this code is for redirecting to the dashboard page with calling ngOnInIt
                  this.router.routeReuseStrategy.shouldReuseRoute = () => false;
                  this.router.onSameUrlNavigation = 'reload';
                  this.router.navigate(['./dashboard']);
              

              这应该有效,并且应该只用于特殊情况。当您在重定向后不必进行太多导航时,您可以使用此。否则有时会搞砸。请注意,您始终可以在需要时将“routeReuseStrategy”设置为 true。

              【讨论】:

                猜你喜欢
                • 2022-07-15
                • 2020-09-11
                • 2018-06-17
                • 2017-02-19
                • 1970-01-01
                • 1970-01-01
                • 2018-08-08
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多