3

I'm currently writing a StencilJS component with a ref to a element, which I need to pass as a @Prop to another element. Like so:

<canvas ref={el => this.canvas = el}></canvas>
<color-picker canvas={this.canvas}></color-picker>

When the color picker gets created, the this.canvas is still undefined, resulting in an error in color-picker.

How can I do this in JSX?

Elger van Boxtel
  • 1,030
  • 12
  • 23

2 Answers2

5

As already mentioned in the other answer, your reference only gets created after the first render, when an actual instance of your element becomes available that the reference can point to.

The simplest way to solve this for you would be to mark the canvas member as state with the @State() decorator (which will trigger a re-render if its reference changes), and then conditionally render the <color-picker /> only once a valid reference is available:

import { h, Component, Host, State } from '@stencil/core';

@Component({ tag: 'my-component' })
export class MyComponent {
  @State() canvas?: HTMLCanvasElement;

  render() {
    return (
      <Host>
        <canvas ref={el => this.canvas = el} />
        {this.canvas && <color-picker canvas={this.canvas} />}
      </Host>
    );
  }
}
Simon Hänisch
  • 4,740
  • 2
  • 30
  • 42
1

this.canvas is a reference to a DOM element, therefore it can only have a value after the initial render.

If you make canvas a @State() property your component will re-render after it is defined (or changed), which will pass it to the color-picker.

Or you could manually re-render your component after it first loaded:

componentDidLoad() {
    this.forceUpdate();
}

The effect will be the same, except that your component won't re-render if canvas gets redefined.

Of course, the color-picker component needs to work with a null canvas.

Thomas
  • 8,426
  • 1
  • 25
  • 49