Angular和React中实现组件的缓存是没有类似vue中的<keep-alive></keep-alive>这种很爽的方式的,但是并不意味着Angular和React不能实现类似的功能,这次angular项目上的需求就遇到了这个问题,具体的需求是:

1. A组件是一个列表组件,该组件上面有CRUD基本功能,其中新建、修改是路由跳转到,一个新的组件中新建和修改;
2. 当数据比较多的时候,用户点击新建或者修改时,但是并没实际的去新建或者修改一条数据,这个时候点击返回或者取消,返回到A组件的时候,A组件就会重新向后台发http请求,这就会影响到性能;
3. 当用户通过多个搜索条件或者在页码数较大的一页中修改某一条数据时,用户修改之后就想看到自己修改的结果并且这里的搜索条件和页码也不能清空,仅仅只要求数据变化;
看到这里的时候,熟悉Vue的同学,脑子立马就想到了,<keep-alive></keep-alive>这个组件了,但是很尴尬的是angular没有这个东西(react也没有),所以只能从其它地方想办法了

解决方案--------路由复用策略
  • 思路: 我的需求总结起来就是,我希望自己的某个组件在我想要它刷新时,它再去刷新,这里就可以从路由这里找突破口,因为我的路由可以说是一个相对固定的值,例如:新建的时候,不需要传参,那这个路由肯定是不变的;编辑的时候,我使用了路由带参,这里带的参数是相对固定的,因为每次编辑的跳转和返回这里带的参数是一样的,知道怎么搞了就可以去实现了;
    1. 首先创建一个类,用来做路由复用策略
	import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
export class RouterReuseStrategy implements RouteReuseStrategy {
  _cacheRouters: { [key: string]: any } = {};
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    // 通过给路由配置项增加data: { keep: true }来进行选择性使用
    if (!route.data.keep) {
      return false;
    } else {
      return true;
    }
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    // 按path作为key存储路由快照&组件当前实例对象
    // path等同RouterModule.forRoot中的配置
    this._cacheRouters[route.routeConfig.path] = {
      snapshot: route,
      handle: handle
    };
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    // 在缓存中有的都认为允许还原路由
    return !!route.routeConfig && !!this._cacheRouters[route.routeConfig.path];
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    // 从缓存中获取快照,若无则返回null
    if (!route.routeConfig || route.routeConfig.loadChildren || !this._cacheRouters[route.routeConfig.path]) return null;
    return this._cacheRouters[route.routeConfig.path].handle;
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    // 同一路由时复用路由
    return future.routeConfig === curr.routeConfig;
  }
}

2. 在自己的module中注入

// 若是整个项目用的很多就直接在主模块中注入
	 providers: [RouterReuseStrategy ]

3. 配置需要缓存的路由

 { path: 'violation-list', component: ViolationListComponent, data: { keep: true } }

4. 在组件中使用

   // 编辑时带的参数
    ID: any;
		  constructor(
    private $router: Router,
    private $violationService: ViolationService,
  ) {
    this.$router.events.pipe(filter(event => event instanceof NavigationStart)).subscribe((event: NavigationStart) => {
      // 判定是否初始化
    //  this.activatedRoute.data.subscribe(res => {});
      if (
      // 若不是新建  编辑  和该页面的路由,就会走ngOnInit()生命周期函数
        this.$router.url !== '/violation-ticket?title=%E6%96%B0%E5%BB%BA%E8%BF%9D%E7%BA%A6%E5%8D%95' &&
        this.$router.url !== '/violation-list' &&
        this.$router.url !== `/violation-ticket?title=%E7%BC%96%E8%BE%91%E8%BF%9D%E7%BA%A6%E5%8D%95&ID=${this.ID}`
      ) {
        this.ngOnInit();
        this.listGroup.reset();
      } 
      // 修改的时候,需要把修改之前组件所在的页码,查询参数等存到一个变量中,在返回之后进行一个http请求,请求修改后的数据
      else if (this.$router.url === `/violation-ticket?title=%E7%BC%96%E8%BE%91%E8%BF%9D%E7%BA%A6%E5%8D%95&ID=${this.ID}`) {
        // 根据编辑时的参数,请求后台的数据
        this.page(this.pageInfo);
      }
    });
  }

现在就完整的实现了上面的需求了,数据不改变不会,数据改变会根据参数的信息才会发请求!

总结
  • 1组件是否更新和如何更新是根据路由的值来决定是否执行生命周期函数ngOnInit(),若是执行了ngOnInit(),页 面就会刷新
  • 2.shouldDetach(ActivatedRouteSnapshot):该函数的作用是:是否缓存(路由离开的时候执行),它的返回值是boolean类型的,当返回值是true时,就表示该路由支持暂存,否则不支持.可以在路由中配置,如上面代码中的:
		// 这里的data: { keep: true }表示该路由支持暂存
		{ path: 'violation-list', component: ViolationListComponent, data: { keep: true } }
    1. store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle):该函数的作用是:缓存组件,离开路由时触发,
  • 4.shouldAttach(route: ActivatedRouteSnapshot):该函数的作用是:判断路由是否需要还原,进入路由的时候触发
  • 5.retrieve(route: ActivatedRouteSnapshot): 该函数的作用是:获取暂存的路由,进入路由时触发
  • 6.shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot):该函数的作用是:是否重复该路由,返回值是boolean类型.返回true则复用,否则不复用.
Logo

前往低代码交流专区

更多推荐