-
Notifications
You must be signed in to change notification settings - Fork 1
Stencil JS Basics

Stencil is a compiler that generates Web Components developed by the Ionic team. Stencil takes popular features such as the Virtual DOM, Typescript and JSX to create standard-based Web components which can be used with every popular frontend framework out of the box (Angular, React, Vue).
-
You can make webcomponents that work across different frameworks; As they're built in an API specific to the browser.
-
StencilJS creates components that are plain javascript but they're not using webcomponent API as they're not extending HTML element ( this would make it bound to browsers / DOM ).
-
components are usually kebab-case.
-
run
npm run generate
"Component" decorators usually have
tagwhich is the HTML tag you'll use in client,styleUrlwhich should point to styles,shadowBoolean, it indicates whether the component has a shadow DOM which means the component HTML doesn't show up in the main DOM, it's mainly used for encapsulation.
"Prop" is used to define props that can be passed to component. Props should be used to pass data down from a parent component to its child component(s).
- A Prop is by default immutable from inside the component logic. Once a value is set by a user, the component cannot update it internally.
- The way a boolean or number prop is passed is different in HTML and TSX.
export class ToDoListItem {
@Prop() isComplete: boolean;
}HTML:
<todo-list-item is-complete="true"></todo-list-item>TSX:
<todo-list-item isComplete={true}></todo-list-item>-
Prop Validation To do validation of a Prop, you can use the @Watch() decorator:
The @Prop() decorator accepts an optional argument to specify certain options to modify how a prop on a component behaves. @Prop()'s optional argument is an object literal containing one or more of the following fields:
export interface PropOptions {
attribute?: string;
mutable?: boolean;
reflect?: boolean;
}example Component
export class ToDoListItem {
@Prop() isComplete: boolean;
@Prop() thingToDo: string;
@Prop() myHttpService: MyHttpService;
}his component has 3 properties, but the compiler will create only 2 attributes: is-complete and thing-to-do.
<todo-list-item is-complete="false" thing-to-do="Read Attribute Naming Section of Stencil Docs"></my-cmp>Notice that the myHttpService type is not a primitive (e.g. not a number, boolean, or string). Since DOM attributes can only be strings, it does not make sense to have an associated DOM attribute called "my-http-service".
this "default" behaviour can be changed using the attribute option of the @Prop() decorator
export class ToDoListItem {
@Prop({ attribute: 'complete' }) isComplete: boolean;
@Prop({ attribute: 'thing' }) thingToDo: string;
@Prop({ attribute: 'my-service' }) myHttpService: MyHttpService;
}<todo-list-item complete="false" thing="Read Attribute Naming Section of Stencil Docs" my-service="{}"></my-cmp>A Stencil component may have one or more internal class members for holding value(s) that make up the component's state
-
Stencil provides a decorator to trigger a rerender when certain class members change. A component's class members that should trigger a rerender must be decorated using Stencil's
@State() -
If you know for sure that the value will either not change or that it does not need to trigger a re-rendering, @State() is not necessary. It is considered a 'best practice' to only use @State() when absolutely necessary.
-
"reassignment" of state is causing the rerender; Mutating the existing reference to state will not cause a rerender, as Stencil will not know the contents of the complex dataType ( array / object ) has changed.
- For example, to push a new item to an array, create a new array with the existing values and the new value at the end:
this.randNumbers = [...this.randNumbers, newVal]
The Listen() decorator is for listening to DOM events, including the ones dispatched from @Events. The event listeners are automatically added and removed when the component gets added or removed from the DOM.
- Stencil components update when props or state on a component change.
@Watch() is a decorator that is applied to a method of a Stencil component. The decorator accepts a single argument, the name of a class member that is decorated with @Prop() or @State(). A method decorated with @Watch() will automatically run when its associated class member changes.
// Apply @Watch() for the component's `busy` member.
// Whenever `busy` changes, this method will fire.
@Watch('busy')
watchStateHandler(newValue: boolean, oldValue: boolean) {
console.log('The old value of busy is: ', oldValue);
console.log('The new value of busy is: ', newValue);
}- When fired, the @Watch()'ed method will receive the old and new values of the prop/state. This is useful for validation or the handling of side effects.
Components have numerous lifecycle methods which can be used to know when the component "will" and "did" load, update, and render. These methods can be added to a component to hook into operations at the right time.
Called every time the component is connected to the DOM. When the component is first connected, this method is called before componentWillLoad.
- this method can be called more than once, every time, the element is attached or moved in the DOM. For logic that needs to run every time the element is attached or moved in the DOM, it is considered a best practice to use this lifecycle method.
Called once just after the component is first connected to the DOM. Since this method is only called once, it's a good place to load data asynchronously and to setup the state without triggering extra re-renders.
- A promise can be returned, that can be used to wait for the first render()
Called once just after the component is fully loaded and the first render() occurs.
This hook is called when a component's Prop or State property changes and a rerender is about to be requested. This hook receives three arguments: the new value, the old value and the name of the changed state. It should return a boolean to indicate if the component should rerender (true) or not (false).
It's always recommended to make any rendered state updates within componentWillRender(), since this is the method which get called before the render() method. Alternatively, updating rendered state with the componentDidLoad(), componentDidUpdate() and componentDidRender() methods will cause another rerender, which isn't ideal for performance.
If state must be updated in componentDidUpdate() or componentDidRender(), it has the potential of getting components stuck in an infinite loop. If updating state within componentDidUpdate() is unavoidable, then the method should also come with a way to detect if the props or state is "dirty" or not (is the data actually different or is it the same as before). By doing a dirty check, componentDidUpdate() is able to avoid rendering the same data, and which in turn calls componentDidUpdate() again.