自定义 Storybook 插件更改后重新渲染组件

Mat*_*ias 5 angular storybook

我有一个使用的自定义附加组件@storybook/angular。每当附加组件中的某些值发生变化时,当前故事中的 Angular 组件就应该重新渲染,因此它应该完全重新初始化。

我尝试使用forceReRender()from @storybook/angular,但它似乎什么也没做。当我选择另一个故事并再次打开前一个故事时,由于组件重新初始化,因此会应用更改。是否也可以从附加组件内部实现此目的?

jos*_*res 1

我在装饰器+工具栏设置方面也遇到了类似的问题。每当我的装饰器更改 中的值时props,我需要强制组件初始化,而不是仅更新绑定并调用更改检测。

所以我添加了一个包装组件来强制故事的重新初始化:

// noinspection AngularMissingOrInvalidDeclarationInModule
/**
 * force the re-rendering of the story's components.
 */
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'sb-force-rendering',
  template: '<ng-container #outlet></ng-container>',
})
export class ForceRenderingComponent implements AfterViewInit, OnDestroy {
  @ContentChild(TemplateRef) public template: TemplateRef<any>
  @ViewChild('outlet', { read: ViewContainerRef }) outletRef: ViewContainerRef

  public static render$: Subject<void> = new Subject<void>()
  private subscription: Subscription = new Subscription()

  constructor(private ngZone: NgZone) {}

  public ngAfterViewInit(): void {
    this.doRender()
    this.subscription.add(ForceRenderingComponent.render$.subscribe(() => this.doRender()))
  }

  public ngOnDestroy(): void {
    this.subscription.unsubscribe()
  }

  private doRender(): void {
    // storybook re-rendering can be triggered outside from the angular zone
    // we need to re-enter the angular zone to ensure the components are still interactive
    this.ngZone.run(() => {
      this.outletRef.clear()
      this.outletRef.createEmbeddedView(this.template)
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

这就是在装饰器中使用该组件的方式:

export const withSiteSwitch = (story: any, context: any) => {
  const site = context.globals.site
  const { moduleMetadata = {}, template = '', props = {}, ...rest } = story()
  const { declarations = [] } = moduleMetadata
  moduleMetadata.declarations = [...declarations, ForceRenderingComponent]
  document.documentElement.setAttribute('site', site)
  ForceRenderingComponent.render$.next() // triggers re-initialization
  return {
    ...rest,
    moduleMetadata,
    props: { ...props, site },
    template: `<sb-force-rendering><ng-template>${template}</ng-template></sb-force-rendering>`,
  }
}
Run Code Online (Sandbox Code Playgroud)