This was presented at GUG Prague js dev meetup www.gug.cz/cs/akce/reactive-type-safe-webcomponents/terminy/1
You know the drill right? new cool framework/library appears... boom! new Datepicker in that framework follows and soon enough whole UI libraries, again and again....
It's 2017 and it's time to stop this madness once and for all! How you ask?
In this talk I will do an overview of component creation in terms of re-usability followed up with real life examples how to create performant, reactive, small and type-safe web components with tiny superpowered library called SkateJS.
Write once, use everywhere by using the platform.
Source code: https://github.com/Hotell/reactive-typesafe-webcomponents
SkateJS: https://github.com/skatejs/skatejs
23. Custom
Elements
class User extends HTMLElement {}
// user.component.js
<sk-user></sk-user>
// index.html
// Global registry
window.customElements.define('sk-user', User)
window.customElements.get('sk-user') // User
30. export class User extends HTMLElement {
_tricks = []
set tricks(value) {
this._tricks = value
this.render()
}
get tricks() {
return this._tricks
}
render() {}
}
// user.component.js
Custom Elements
API
Attributes
&
Properties
Rich
Data
31. export class User extends HTMLElement {
_tricks = []
set tricks(value) {
this._tricks = value
this.render()
}
get tricks() {
return this._tricks
}
render() {}
}
// user.component.js
Custom Elements
API
Attributes
&
Properties
Rich
Data
32. export class User extends HTMLElement {
_tricks = []
set tricks(value) {
this._tricks = value
this.render()
}
get tricks() {
return this._tricks
}
render() {}
}
// user.component.js
Custom Elements
API
Attributes
&
Properties
Rich
Data
33. // $0 === User instance
$0.addEventListener('learntrick',(event)=>{ /* ... */ })
// Imperative (JS)
Nope
// Declarative (HTML)
Custom Elements
API
Events
34. export class User extends HTMLElement {
emitLearnTrick(trick) {
const eventConfig = {
bubble: true,
composed: false,
detail: trick
}
const event = new CustomEvent('learntrick', eventConfig)
this.dispatchEvent(event)
}
}
// user.component.js
Custom Elements
API
Events
35. export class User extends HTMLElement {
constructor() {
super()
}
attributeChangedCallback(name, oldValue, newValue) {
// do some stuff
}
connectedCallback() {
console.log('component mounted!')
}
disconnectedCallback() {
console.log('goodbye!')
}
render() {}
}
// user.component.js
Custom Elements
API
Life Cycle
Hooks
36. export class User extends HTMLElement {
constructor() {
super()
}
attributeChangedCallback(name, oldValue, newValue) {
// do some stuff
}
connectedCallback() {
console.log('component mounted!')
}
disconnectedCallback() {
console.log('goodbye!')
}
render() {}
}
// user.component.js
Custom Elements
API
Life Cycle
Hooks
37. export class User extends HTMLElement {
constructor() {
super()
}
attributeChangedCallback(name, oldValue, newValue) {
// do some stuff
}
connectedCallback() {
console.log('component mounted!')
}
disconnectedCallback() {
console.log('goodbye!')
}
render() {}
}
// user.component.js
Custom Elements
API
Life Cycle
Hooks
38. export class User extends HTMLElement {
constructor() {
super()
}
attributeChangedCallback(name, oldValue, newValue) {
// do some stuff
}
connectedCallback() {
console.log('component mounted!')
}
disconnectedCallback() {
console.log('goodbye!')
}
render() {}
}
// user.component.js
Custom Elements
API
Life Cycle
Hooks
39. export class User extends HTMLElement {
constructor() {
super()
}
attributeChangedCallback(name, oldValue, newValue) {
// do some stuff
}
connectedCallback() {
console.log('component mounted!')
}
disconnectedCallback() {
console.log('goodbye!')
}
render() {}
}
// user.component.js
Custom Elements
API
Life Cycle
Hooks
105. Advanced Tricks
- State like React
- No default renderer in core ✅
- Mixins for everything - ✅
- API for turning off ShadowDOM - ✅
- Server side rendering - ✅
- Testing with Jest - ✅