[フレーム]
Skip to main content
An OutSystems Company →
This is unreleased documentation for Stencil Next version.
For up-to-date documentation, see the latest version (v4.40).
Version: Next

Serialization & Deserialization

Custom elements interact with the DOM either via HTML attributes (always strings) or JavaScript properties. Stencil automatically tries to keep properties and attributes in-sync when possible via serialization (turning properties into strings) and deserialization (turning strings back into properties).

For example, if you have a component defined like this:

@Component({
tag:'my-component',
})
exportclassMyComponent{
// Stencil 'sees' this as a number type.
// Numbers are easy to convert to/from strings
@Prop({ reflect:true}) myNumber:number;
}

When the property is set via JavaScript:

const myComponent = document.querySelector('my-component');
myComponent.myNumber =42;

Stencil will automatically serialize myNumber to an attribute:

<my-componentmy-number="42"></my-component>

Conversely, if the attribute is set in HTML:

<!-- in html -->
<my-componentmy-number="42"></my-component>
<!-- or js -->
<script>
const myComponent = document.querySelector('my-component');
myComponent.setAttribute('my-number', '43');
</script>

Stencil will automatically deserialize the attribute back to the property:

console.log(myComponent.myNumber);// 43

Most of the time Stencil's automatic serialization and deserialization is enough - especially with primitive data types, however there are cases where you might want to customize this behavior, especially when dealing with complex data.

The PropSerialize Decorator (@PropSerialize())

The @PropSerialize() decorator allows you to define custom serialization logic; converting a JavaScript property to a attribute string. The decorator accepts a single argument; the name of the class member @Prop() it is associated with. A method decorated with @PropSerialize() will automatically run when its associated property changes.

import{Component,Prop,PropSerialize}from'@stencil/core';

@Component({
tag:'my-component',
})
exportclassMyComponent{
@Prop() aStringArray:string[];

@PropSerialize('aStringArray')
serializeStringArray(value:string[]){
try{
returnJSON.stringify(value);// must return a string
}catch(e){
returnnull;// returning null removes the attribute
}
}
}

In the example above, the serializeStringArray method will run whenever the aStringArray property changes - the returned value will be used to update the attribute (no need to set {reflect: true} on the @Prop() decorator). E.g.

const myComponent = document.querySelector('my-component');
myComponent.aStringArray =['Hello','World'];

Becomes:

<my-componenta-string-array='["Hello","World"]'></my-component>

The AttrDeserialize Decorator (@AttrDeserialize())

The @AttrDeserialize() decorator allows you to define custom deserialization logic; converting an attribute string to a JavaScript property. The decorator accepts a single argument; the name of the class member @Prop() it is associated with. A method decorated with @AttrDeserialize() will automatically run when its associated attribute changes.

import{Component,Prop,AttrDeserialize}from'@stencil/core';

@Component({
tag:'my-component',
})
exportclassMyComponent{
@Prop() aStringArray:string[];

@AttrDeserialize('aStringArray')
deserializeStringArray(value:string):string[]|null{
try{
returnJSON.parse(value);
}catch(e){
returnnull;
}
}
}

In the example above, the deserializeStringArray method will run whenever the a-string-array attribute changes. The method takes the new value of the attribute as an argument and must return the deserialized value.

Now, when you set the attribute in HTML:

<my-componenta-string-array='["Hello","World"]'></my-component>

Stencil will automatically deserialize the attribute back to the property:

const myComponent = document.querySelector('my-component');
console.log(myComponent.aStringArray);// ['Hello', 'World']

Practical uses of PropSerialize

Practically speaking, there is little disadvantage in using a @AttrDeserialize() on a complex property; it just adds another method for users to provide data to your component.

The use-cases around using @PropSerialize() is slightly less obvious as in general, it is not considered best practice to reflect complex data (like objects or arrays) as attributes

The following example illustrates a practical use case for @PropSerialize() using the hydrate script output on a server we can fetch and serialize complex data to an attribute. When the same component loads in a browser, the component can de-serialize the data immediately without having to do another fetch.

import{AttrDeserialize,Build,Component, h,Prop,PropSerialize}from'@stencil/core';

interfaceUser{
userName:string;
avatarUrl:string;
posts:any[]
}

@Component({
tag:'user-login-panel',
})
exportclassUserLogin{
@Prop() user:User;

// On the server *only* let's represent the user's data as an attribute
// this allows the browser to get the data immediately without having to do a client-side fetch

@PropSerialize('user')
userSerialize(newVal:User){
if(Build.isBrowser){
returnnull;
}
try{returnJSON.stringify(newVal);}
catch(e){returnnull;}
}

// Whenever we have an attribute (including on client init)
// let's turn it back into an object that we can use and render

@AttrDeserialize('user')
userDeserialize(newVal:string){
try{returnJSON.parse(newVal);}
catch(e){returnnull;}
}

asynccomponentWillLoad(){

// On the server *only*, let's do a secret login involving private keys etc.

if(Build.isServer){
// Because we have a serializer method,
// setting a value automatically reflects it to the dom attribute

this.user=login(credentials);
}
}

render(){
if(this.user)return(`Welcome ${this.user.userName}!`);
elsereturn(`Please login`);
}
}

AltStyle によって変換されたページ (->オリジナル) /