Stencil: Slow render performance after React and Ember integration

Created on 2 Jul 2019  路  4Comments  路  Source: ionic-team/stencil

Stencil version:

 @stencil/[email protected] and all older

I'm submitting a:

[x] bug report
[ ] feature request
[ ] support request
Current behavior:

I have projects in Ember and React. I created a library of Stencil components with components like:

  • text (changing size/colors/weight via props)
  • select
  • multiselect
  • textfield

I replaced Ember and React components with brand new Stencil components. I observed performance problems after this replacement. You can see differences in linked videos. First for old, React components, second for Stencil.

https://www.youtube.com/watch?v=fyLq41L3CCc
https://www.youtube.com/watch?v=A23JFnCYxro

The problem occurs both in Ember and React.

Render is slower in an unacceptable way. In youtube example, the difference is really small, but for 30 rows dashboard, the final result is visible 1.5 seconds later.

Observations in my app context:

  • problem with rendering dashboard rows - each cell has a text component to format the text properly
  • problem with rendering advance search - few fields should appear after clicking button

Expected behavior:

Rendering should be at least that quick as in original components

Steps to reproduce:

Create a container with several stencil components. Show/hide this container using a button with simple action and conditional statement in your template

Related code:

Example of usage:

<BF sizeSm={2}>
  <select
    optionNameField={'name'}
    onSelect={this.onChange}
    optionsArray={this.props.names}
    valueObject={this.state.selectedName}
  />
</BF>
<BF sizeSm={3}>
  <ac-multiselect
    optionsArray={this.props.types}
    valuesArray={this.state.selectedTypes}
    onChangeHandler={this.onChangeType}
    optionNameField="name"
    optionValueField="type"
  />
</BF>

Example of component implementation:

export class Text implements ComponentInterface {
  @Prop({ reflect: true }) color: TextColor = TextColor.black;
  @Prop({ reflect: true }) size: TextSize = TextSize.md;
  @Prop({ reflect: true }) weight: TextWeight = TextWeight.normal;
  @Prop({ reflect: true }) uppercase: boolean;

  private colorClass(): string {
    return `text-color-${this.color}`;
  }

  private sizeClass(): string {
    return `text-size-${this.size}`;
  }

  private weightClass(): string {
    return `text-weight-${this.weight}`;
  }

  private uppercaseClass(): string {
    return this.uppercase ? 'text-uppercase' : '';
  }

  private classes(): string[] {
    return [
      this.sizeClass(),
      this.weightClass(),
      this.colorClass(),
      this.uppercaseClass()
    ].filter(Boolean);
  }

  render() {
    return (
      <Host class={{ ...getClassMap(this.classes()) }}>
        <slot />
      </Host>
    );
  }
}

Other information:

I did a simple performance test. Render 1000 components (text field) on the plain React page. Stencil was faster than React. Problem is appearing only when I'm using components in a regular structure.

triage

Most helpful comment

We're running into similar issues where updates in the state of a component that renders child components shows a flash of unstyled content even for child components that are already lazy loaded.

All 4 comments

We're running into similar issues where updates in the state of a component that renders child components shows a flash of unstyled content even for child components that are already lazy loaded.

Is the bottleneck related to virtual dom? would it be faster if stencil is built with svelte.js?

I don't think so, I turned off virtual DOM

try removing the reflect: true on the component and see if this improves things, seeing similar issues.

Was this page helpful?
0 / 5 - 0 ratings