-
Notifications
You must be signed in to change notification settings - Fork 421
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this commit is the result of running ```bash $ npm run docusaurus docs:version v4.6 ```
- Loading branch information
1 parent
41951b2
commit 1577c5b
Showing
87 changed files
with
12,354 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"label": "Components", | ||
"position": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
183
versioned_docs/version-v4.7/components/component-lifecycle.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} | ||
} | ||
``` |
Oops, something went wrong.