Skip to content

Commit

Permalink
docs(v4.7): add v4.7 documentation
Browse files Browse the repository at this point in the history
this commit is the result of running
```bash
$ npm run docusaurus docs:version v4.6
```
  • Loading branch information
rwaskiewicz committed Oct 30, 2023
1 parent 41951b2 commit 1577c5b
Show file tree
Hide file tree
Showing 87 changed files with 12,354 additions and 0 deletions.
48 changes: 48 additions & 0 deletions versioned_docs/version-v4.7/build-variables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Build Constants
description: Stencil has a number of add-ons that you can use with the build process.
slug: /build-variables
---

# Build Constants

Build Constants in Stencil allow you to run specific code only when Stencil is running in development mode. This code is stripped from your bundles when doing a production build, therefore keeping your bundles as small as possible.

### Using Build Constants

Lets dive in and look at an example of how to use our build constants:

```tsx
import { Component, Build } from '@stencil/core';

@Component({
tag: 'stencil-app',
styleUrl: 'stencil-app.scss'
})
export class StencilApp {

componentDidLoad() {
if (Build.isDev) {
console.log('im in dev mode');
} else {
console.log('im running in production');
}

if (Build.isBrowser) {
console.log('im in the browser');
} else {
console.log('im in prerendering (server)');
}
}
}
```

As you can see from this example, we just need to import `Build` from `@stencil/core` and then we can use the `isDev` constant to detect when we are running in dev mode or production mode.

### Use Cases

Some use cases we have come up with are:

- Diagnostics code that runs in dev to make sure logic is working like you would expect
- `console.log()`'s that may be useful for debugging in dev mode but that you don't want to ship
- Disabling auth checks when in dev mode
4 changes: 4 additions & 0 deletions versioned_docs/version-v4.7/components/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Components",
"position": 2
}
97 changes: 97 additions & 0 deletions versioned_docs/version-v4.7/components/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: Component API
sidebar_label: API
description: Component API
slug: /api
---

# Component API

The whole API provided by stencil can be condensed in a set of decorators, lifecycles hooks and rendering methods.


## Decorators

Decorators are a pure compiler-time construction used by stencil to collect all the metadata about a component, the properties, attributes and methods it might expose, the events it might emit or even the associated stylesheets.
Once all the metadata has been collected, all the decorators are removed from the output, so they don't incur any runtime overhead.

- [@Component()](./component.md#component-decorator) declares a new web component
- [@Prop()](./properties.md#the-prop-decorator-prop) declares an exposed property/attribute
- [@State()](./state.md#the-state-decorator-state) declares an internal state of the component
- [@Watch()](./reactive-data.md#the-watch-decorator-watch) declares a hook that runs when a property or state changes
- [@Element()](./host-element.md#element-decorator) declares a reference to the host element
- [@Method()](./methods.md#method-decorator) declares an exposed public method
- [@Event()](./events.md#event-decorator) declares a DOM event the component might emit
- [@Listen()](./events.md#listen-decorator) listens for DOM events


## Lifecycle hooks

- [connectedCallback()](./component-lifecycle.md#connectedcallback)
- [disconnectedCallback()](./component-lifecycle.md#disconnectedcallback)
- [componentWillLoad()](./component-lifecycle.md#componentwillload)
- [componentDidLoad()](./component-lifecycle.md#componentdidload)
- [componentShouldUpdate(newValue, oldValue, propName): boolean](./component-lifecycle.md#componentshouldupdate)
- [componentWillRender()](./component-lifecycle.md#componentwillrender)
- [componentDidRender()](./component-lifecycle.md#componentdidrender)
- [componentWillUpdate()](./component-lifecycle.md#componentwillupdate)
- [componentDidUpdate()](./component-lifecycle.md#componentdidupdate)
- **[render()](./templating-and-jsx.md)**

## componentOnReady()

This isn't a true "lifecycle" method that would be declared on the component class definition, but instead is a utility method that
can be used by an implementation consuming your Stencil component to detect when a component has finished its first render cycle.

This method returns a promise which resolves after `componentDidRender()` on the _first_ render cycle.

:::note
`componentOnReady()` only resolves once per component lifetime. If you need to hook into subsequent render cycle, use
`componentDidRender()` or `componentDidUpdate()`.
:::

Executing code after `componentOnReady()` resolves could look something like this:

```ts
// Get a reference to the element
const el = document.querySelector('my-component');

el.componentOnReady().then(() => {
// Place any code in here you want to execute when the component is ready
console.log('my-component is ready');
});
```

The availability of `componentOnReady()` depends on the component's compiled output type. This method is only available for lazy-loaded
distribution types ([`dist`](../output-targets/dist.md) and [`www`](../output-targets/www.md)) and, as such, is not available for
[`dist-custom-elements`](../output-targets/custom-elements.md) output. If you want to simulate the behavior of `componentOnReady()` for non-lazy builds,
you can implement a helper method to wrap the functionality similar to what the Ionic Framework does [here](https://github.com/ionic-team/ionic-framework/blob/main/core/src/utils/helpers.ts#L60-L79).

## The `appload` event

In addition to component-specific lifecycle hooks, a special event called `appload` will be emitted when the app and all of its child components have finished loading. You can listen for it on the `window` object.

If you have multiple apps on the same page, you can determine which app emitted the event by checking `event.detail.namespace`. This will be the value of the [namespace config option](../config/01-overview.md#namespace) you've set in your Stencil config.

```tsx
window.addEventListener('appload', (event) => {
console.log(event.detail.namespace);
});
```

## Other

- [**Host**](./host-element.md): Host is a functional component that can be used at the root of the render function to set attributes and event listeners to the host element itself.

- [**h()**](./templating-and-jsx.md): It's used within the `render()` to turn the JSX into Virtual DOM elements.

- [**readTask()**](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing): Schedules a DOM-read task. The provided callback will be executed in the best moment to perform DOM reads without causing layout thrashing.

- [**writeTask()**](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing): Schedules a DOM-write task. The provided callback will be executed in the best moment to perform DOM mutations without causing layout thrashing.

- **forceUpdate()**: Schedules a new render of the given instance or element even if no state changed. Notice `forceUpdate()` is not synchronous and might perform the DOM render in the next frame.

- getAssetPath(): Gets the path to local assets. Refer to the [Assets](../guides/assets.md#getassetpath) page for usage info.
- setMode()
- getMode()
- getElement()
183 changes: 183 additions & 0 deletions versioned_docs/version-v4.7/components/component-lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
title: Component Lifecycle Methods
sidebar_label: Lifecycle Methods
description: Component Lifecycle Methods
slug: /component-lifecycle
---

# Component Lifecycle Methods

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.

Implement one of the following methods within a component class and Stencil will automatically call them in the right order:

import LifecycleMethodsChart from '@site/src/components/LifecycleMethodsChart';

<LifecycleMethodsChart />

## connectedCallback()

Called every time the component is connected to the DOM.
When the component is first connected, this method is called before `componentWillLoad`.

It's important to note that 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.

```tsx
const el = document.createElement('my-cmp');
document.body.appendChild(el);
// connectedCallback() called
// componentWillLoad() called (first time)

el.remove();
// disconnectedCallback()

document.body.appendChild(el);
// connectedCallback() called again, but `componentWillLoad()` is not.
```


This `lifecycle` hook follows the same semantics as the one described by the [Custom Elements Spec](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements)

## disconnectedCallback()

Called every time the component is disconnected from the DOM, ie, it can be dispatched more than once, DO not confuse with a "onDestroy" kind of event.

This `lifecycle` hook follows the same semantics as the one described by the [Custom Elements Spec](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements).

## componentWillLoad()

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()`.

## componentDidLoad()

Called once just after the component is fully loaded and the first `render()` occurs.

## componentShouldUpdate()

This hook is called when a component's [`Prop`](./properties.md) or [`State`](./state.md) 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`).

A couple of things to notice is that this method will not be executed before the initial render, that is, when the component is first attached to the dom, nor when a rerender is already scheduled in the next frame.

Let’s say the following two props of a component change synchronously:

```tsx
component.somePropA = 42;
component.somePropB = 88;
```

The `componentShouldUpdate` will be first called with arguments: `42`, `undefined` and `somePropA`. If it does return `true`, the hook will not be called again since the rerender is already scheduled to happen. Instead, if the first hook returned `false`, then `componentShouldUpdate` will be called again with `88`, `undefined` and `somePropB` as arguments, triggered by the `component.somePropB = 88` mutation.

Since the execution of this hook might be conditioned, it's not good to rely on it to watch for prop changes, instead use the `@Watch` decorator for that.

## componentWillRender()

Called before every `render()`.

A promise can be returned, that can be used to wait for the upcoming render.

## componentDidRender()

Called after every `render()`.


## componentWillUpdate()

Called when the component is about to be updated because some `Prop()` or `State()` changed.
It's never called during the first `render()`.

A promise can be returned, that can be used to wait for the next render.


## componentDidUpdate()

Called just after the component updates.
It's never called during the first `render()`.


## Rendering State

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.


## Lifecycle Hierarchy

A useful feature of lifecycle methods is that they take their child component's lifecycle into consideration too. For example, if the parent component, `cmp-a`, has a child component, `cmp-b`, then `cmp-a` isn't considered "loaded" until `cmp-b` has finished loading. Another way to put it is that the deepest components finish loading first, then the `componentDidLoad()` calls bubble up.

It's also important to note that even though Stencil can lazy-load components, and has asynchronous rendering, the lifecycle methods are still called in the correct order. So while the top-level component could have already been loaded, all of its lifecycle methods are still called in the correct order, which means it'll wait for a child components to finish loading. The same goes for the exact opposite, where the child components may already be ready while the parent isn't.

In the example below we have a simple hierarchy of components. The numbered list shows the order of which the lifecycle methods will fire.

```markup
<cmp-a>
<cmp-b>
<cmp-c></cmp-c>
</cmp-b>
</cmp-a>
```

1. `cmp-a` - `componentWillLoad()`
2. `cmp-b` - `componentWillLoad()`
3. `cmp-c` - `componentWillLoad()`
4. `cmp-c` - `componentDidLoad()`
5. `cmp-b` - `componentDidLoad()`
6. `cmp-a` - `componentDidLoad()`

Even if some components may or may not be already loaded, the entire component hierarchy waits on its child components to finish loading and rendering.


## Async Lifecycle Methods

Lifecycle methods can also return promises which allows the method to asynchronously retrieve data or perform any async tasks. A great example of this is fetching data to be rendered in a component. For example, this very site you're reading first fetches content data before rendering. But because `fetch()` is async, it's important that `componentWillLoad()` returns a `Promise` to ensure its parent component isn't considered "loaded" until all of its content has rendered.

Below is a quick example showing how `componentWillLoad()` is able to have its parent component wait on it to finish loading its data.

```tsx
componentWillLoad() {
return fetch('/some-data.json')
.then(response => response.json())
.then(data => {
this.content = data;
});
}
```


## Example

This simple example shows a clock and updates the current time every second. The timer is started when the component is added to the DOM. Once it's removed from the DOM, the timer is stopped.

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

@Component({
tag: 'custom-clock'
})
export class CustomClock {

timer: number;

@State() time: number = Date.now();

connectedCallback() {
this.timer = window.setInterval(() => {
this.time = Date.now();
}, 1000);
}

disconnectedCallback() {
window.clearInterval(this.timer);
}

render() {
const time = new Date(this.time).toLocaleTimeString();

return (
<span>{ time }</span>
);
}
}
```
Loading

0 comments on commit 1577c5b

Please sign in to comment.