Bu codelab hakkında
1. Giriş
Edebiyat nedir?
Lit, herhangi bir çerçevede çalışan veya hiçbir çerçeve olmadan çalışan hızlı ve hafif web bileşenleri oluşturmaya yönelik basit bir kitaplıktır. Lit'i kullanarak paylaşılabilir bileşenler, uygulamalar, tasarım sistemleri ve daha fazlasını oluşturabilirsiniz.
Neler öğreneceksiniz?
Çeşitli React kavramlarını Edebiyata dönüştürme, örneğin:
- JSX ve Şablon oluşturma
- Bileşenler ve Dekorlar
- Eyalet & Yaşam döngüsü
- Kancalar
- Çocuklar
- Referanslar
- Arabuluculuk Durumu
Neler oluşturacaksınız?
Bu codelab'in sonunda React bileşeni kavramlarını Lit analoglarına dönüştürebileceksiniz.
Gerekenler
- Chrome, Safari, Firefox veya Edge'in en son sürümü.
- HTML, CSS, JavaScript ve Chrome Geliştirici Araçları hakkında bilgi sahibi olmak.
- Tepki Bilgisi
- (Gelişmiş) En iyi geliştirme deneyimi için VS Code'u indirin. Ayrıca VS Code ve NPM için lit-plugin'e ihtiyacınız vardır.
2. Edebiyat - Tepki
Lit'in temel kavramları ve yetenekleri React'in temel kavramlarına pek çok açıdan benzer ancak Lit'in bazı temel farklılıkları ve farkları da vardır:
Bu küçük
Özet çok küçük: React + ReactDOM'un 40+ kb'ye kıyasla küçültülmüş ve gzip'li boyutu yaklaşık 5 kb'dir.
Hızlı
Lit'in şablon oluşturma sistemi olan lit-html'i React'in VDOM'siyle karşılaştıran herkese açık karşılaştırmalarda lit-html, en kötü durumda React'e kıyasla % 8-10 ve daha yaygın kullanım alanlarında %50+ daha hızlı sunulur.
LitElement (Lit'in bileşen temel sınıfı), lit-html'e minimum ek yük ekler ancak bellek kullanımı, etkileşim ve başlatma süreleri gibi bileşen özelliklerini karşılaştırırken React'in performansını%16-30 oranında artırır.
Derleme gerektirmez
ES modülleri ve etiketli şablon değişmez değerleri gibi yeni tarayıcı özellikleri sayesinde Lit'in çalıştırılması için derleme gerekmez. Bu, geliştirici ortamlarının bir komut dosyası etiketi, tarayıcı + sunucuyla ayarlanabileceği anlamına gelir ve artık çalışmaya hazır olursunuz.
İspanyolca modülleri ve Skypack veya UNPKG gibi modern CDN'ler sayesinde, başlamak için NPM'ye bile ihtiyacınız olmayabilir.
Yine de isterseniz lit kodunu oluşturmaya ve optimize etmeye devam edebilirsiniz. Yerel ES modülleri etrafında kısa süre önce yapılan geliştirici birleştirmesi Lit için iyi oldu. Lit yalnızca normal JavaScript'tir ve çerçeveye özel KSA'lara veya derleme işlemeye gerek yoktur.
Çerçeveden bağımsız
Lit'in bileşenleri, Web Bileşenleri adı verilen bir dizi web standardını temel alır. Bu durum, Lit'te bir bileşen oluşturmanın mevcut ve gelecekteki çerçevelerde işe yarayacağı anlamına gelir. HTML öğelerini destekliyorsa Web Bileşenleri'ni destekler.
Çerçeve birlikte çalışmayla ilgili tek sorun, çerçevelerin DOM için kısıtlayıcı desteğine sahip olmasıdır. React, bu çerçevelerden biridir ancak Refs ile kaçış yolu kullanılmasına olanak tanır. React in React iyi bir geliştirici deneyimi değildir.
Lit ekibi, @lit-labs/react
adlı deneysel bir proje üzerinde çalışıyor. Bu proje, Lit bileşenlerinizi otomatik olarak ayrıştıracak ve referansları kullanmak zorunda kalmamanız için bir React sarmalayıcısı oluşturacak.
Ayrıca Custom Elements Her Yerde, hangi çerçeve ve kitaplıkların özel öğelerle düzgün çalıştığını gösterir.
Birinci sınıf TypeScript desteği
Tüm Lit kodunuzu JavaScript'te yazabilseniz de Lit, TypeScript'te yazılmıştır ve Lit ekibi, geliştiricilerin de TypeScript'i kullanmasını önerir.
Lit ekibi, lit-analyzer
ve lit-plugin
ile hem geliştirme hem de derleme zamanında TypeScript tür denetimi ve zekasını Lit şablonlarına getiren projelerin sürdürülmesine yardımcı olmak için Lit topluluğuyla çalışıyor.
Geliştirici araçları tarayıcıda yerleşiktir
Temel bileşenler yalnızca DOM'de bulunan HTML öğeleridir. Diğer bir deyişle, bileşenlerinizi incelemek için tarayıcınıza yönelik herhangi bir araç veya uzantı yüklemenize gerek yoktur.
Yalnızca geliştirme araçlarını açabilir, bir öğe seçebilir ve özelliklerini veya durumunu inceleyebilirsiniz.
Sunucu tarafı oluşturma (SSR) göz önünde bulundurularak tasarlanmıştır
Lit 2, SSR desteği göz önünde bulundurularak tasarlanmıştır. Bu codelab'in yazıldığı sırada Lit ekibi SSR araçlarını kararlı bir biçimde henüz kullanıma sunmamıştır. Ancak Lit ekibi halihazırda Google ürünleri genelinde sunucu tarafında oluşturulan bileşenleri dağıtmıştır ve React uygulamalarında SSR'yi test etmiştir. Lit ekibi bu araçları yakında GitHub'da harici olarak kullanıma sunmayı umuyor.
Bu sırada Edebiyat ekibinin kaydettiği ilerlemeyi buradan takip edebilirsiniz.
Katılımı azdır.
Edebiyat, kullanmak için büyük bir taahhüt gerektirmez. Lit'te bileşenler derleyebilir ve mevcut projenize ekleyebilirsiniz. Web bileşenleri başka çerçevelerde çalıştığından uygulamayı beğenmezseniz uygulamanın tamamını aynı anda dönüştürmeniz gerekmez.
Lit'te bir uygulama geliştirdiniz mi ve başka bir uygulamaya geçmek mi istiyorsunuz? O zaman mevcut Lit uygulamanızı yeni çerçevenizin içine yerleştirip dilediğiniz her şeyi yeni çerçevenin bileşenlerine taşıyabilirsiniz.
Ayrıca birçok modern çerçeve, web bileşenlerinde çıktıları destekler, yani genellikle Lit öğesinin içine sığabilirler.
3. Kurulum ve Playground'u keşfediyor
Bu codelab'i iki şekilde yapabilirsiniz:
- Tamamen çevrimiçi olarak, tarayıcınızdan yapabilirsiniz.
- (Gelişmiş) Bu işlemi VS Code'u kullanarak yerel makinenizde yapabilirsiniz
Koda erişme
Codelab boyunca Edebiyat oyun alanına şu şekilde bağlantılar verilecektir:
Oyun alanı, tamamen tarayıcınızda çalışan bir kod korumalı alanıdır. TypeScript ve JavaScript dosyalarını derleyip çalıştırabilir, ayrıca düğüm modüllerine yapılan içe aktarmaları otomatik olarak çözümleyebilir. ör.
// before
import './my-file.js';
import 'lit';
// after
import './my-file.js';
import 'https://cdn.skypack.dev/lit';
Bu kontrol noktalarını başlangıç noktaları olarak kullanarak eğitici içeriğin tamamını Edebiyat oyun alanında uygulayabilirsiniz. VS Code kullanıyorsanız bu kontrol noktalarını herhangi bir adımın başlangıç kodunu indirmek için kullanabilir ve ayrıca bunları çalışmanızı kontrol etmek için de kullanabilirsiniz.
Işıklı oyun alanının kullanıcı arayüzünü keşfetmek
Lit Gaming kullanıcı arayüzü ekran görüntüsünde, bu codelab'de kullanacağınız bölümler vurgulanmaktadır.
- Dosya seçici. Artı düğmesine dikkat edin...
- Dosya düzenleyici.
- Kod önizlemesi.
- Yeniden yükle düğmesi.
- İndir düğmesi.
VS Kod kurulumu (Gelişmiş)
Bu VS Code kurulumunu kullanmanın avantajları şunlardır:
- Şablon türü kontrolü
- Şablon zekası ve otomatik tamamlama
NPM, VS Code (lit-plugin eklentisiyle) yüklüyse ve bu ortamı nasıl kullanacağınızı biliyorsanız, aşağıdakileri yaparak bu projeleri indirip başlatmanız yeterlidir:
- İndir düğmesine basın
- tar dosyasının içeriğini bir dizine çıkarın
- (TS varsa) es modülleri ve es2015+ komutlarını döndüren hızlı bir tsconfig ayarlayın
- Yalın modül tanımlayıcıları çözümleyebilen bir geliştirici sunucusu yükleyin (Lit ekibi @web/dev-server'ı önerir)
- Örnek
package.json
- Örnek
- Geliştirici sunucusunu çalıştırın ve tarayıcınızı açın (@web/dev-server kullanıyorsanız
npx web-dev-server --node-resolve --watch --open
öğesini kullanabilirsiniz)package.json
örneğini kullanıyorsanıznpm run dev
kullanın.
4. JSX ve Şablon oluşturma
Bu bölümde Edebiyat'ta şablon oluşturmanın temellerini öğreneceksiniz.
JSX ve Lit şablonları
JSX, React kullanıcılarının JavaScript kodlarında kolayca şablon yazmalarına olanak tanıyan bir JavaScript söz dizimi uzantısıdır. Basit şablonlar da benzer bir amaca hizmet eder: Bileşenin kullanıcı arayüzünü, kendi durumunun işlevi olarak ifade etmek.
Temel Söz Dizimi
React'te şuna benzer bir JSX hello world oluşturursunuz:
import 'react';
import ReactDOM from 'react-dom';
const name = 'Josh Perez';
const element = (
<>
<h1>Hello, {name}</h1>
<div>How are you?</div>
</>
);
ReactDOM.render(
element,
mountNode
);
Yukarıdaki örnekte iki öğe ve bir "name" öğesi eklenmiştir değişkenine eklenmelidir. Edebiyat'ta şunları yaparsınız:
import {html, render} from 'lit';
const name = 'Josh Perez';
const element = html`
<h1>Hello, ${name}</h1>
<div>How are you?</div>`;
render(
element,
mountNode
);
Lit şablonlarının, şablonlarında birden fazla öğeyi gruplandırmak için Tepki Parçası'na ihtiyacı olmadığına dikkat edin.
Lit'te şablonlar html
etiketli şablonla LITelal sarmalanır. Bu şablon da Lit'in adını taşır.
Şablon Değerleri
Lit şablonları, TemplateResult
olarak bilinen diğer Lit şablonlarını kabul edebilir. Örneğin, name
öğesini italik (<i>
) etiketleri içine alın ve N.B etiketli bir düz şablon şablonuyla sarmalayın.Tek tırnak karakterini ('
) değil, vurgu işareti karakterini (`
) kullandığınızdan emin olun.
import {html, render} from 'lit';
const name = html`<i>Josh Perez</i>`;
const element = html`
<h1>Hello, ${name}</h1>
<div>How are you?</div>`;
render(
element,
mountNode
);
Lit TemplateResult
öğeleri dizi, dize ve diğer TemplateResult
öğelerinin yanı sıra yönergeleri de kabul edebilir.
Alıştırma için aşağıdaki React kodunu Lit'e dönüştürmeyi deneyin:
const itemsToBuy = [
<li>Bananas</li>,
<li>oranges</li>,
<li>apples</li>,
<li>grapes</li>
];
const element = (
<>
<h1>Things to buy:</h1>
<ol>
{itemsToBuy}
</ol>
</>);
ReactDOM.render(
element,
mountNode
);
Yanıt:
import {html, render} from 'lit';
const itemsToBuy = [
html`<li>Bananas</li>`,
html`<li>oranges</li>`,
html`<li>apples</li>`,
html`<li>grapes</li>`
];
const element = html`
<h1>Things to buy:</h1>
<ol>
${itemsToBuy}
</ol>`;
render(
element,
mountNode
);
Pas oluşturma ve döşeme sahneleri
JSX ile Lit'in söz dizimleri arasındaki en büyük farklardan biri, veri bağlama söz dizimidir. Örneğin, bağlamaları olan şu React girişini alın:
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element =
<input
disabled={disabled}
className={`static-class ${myClass}`}
defaultValue={value}/>;
ReactDOM.render(
element,
mountNode
);
Yukarıdaki örnekte, aşağıdakileri yapan bir giriş tanımlanır:
- Tanımlanmış bir değişkene devre dışı bırakılır (bu durumda yanlış)
- Sınıfı
static-class
ve bir değişken (bu örnekte"static-class my-class"
) olarak ayarlar - Varsayılan değer ayarlar
Edebiyat'ta şunları yaparsınız:
import {html, render} from 'lit';
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element = html`
<input
?disabled=${disabled}
class="static-class ${myClass}"
.value=${value}>`;
render(
element,
mountNode
);
Edebiyat örneğinde, disabled
özelliğini açıp kapatmak için bir boole bağlaması eklenmiştir.
Ardından, className
yerine doğrudan class
özelliği ile bir bağlama bulunur. Sınıfları değiştirmek için bildirim temelli bir yardımcı olan classMap
yönergesini kullanmıyorsanız class
özelliğine birden fazla bağlama ekleyebilirsiniz.
Son olarak, value
özelliği girişte ayarlanır. React'in aksine bu işlem, girişin yerel uygulamasını ve davranışını takip ettiğinden giriş öğesini salt okunur olarak ayarlamaz.
Lit prop bağlama söz dizimi
html`<my-element ?attribute-name=${booleanVar}>`;
?
öneki, bir öğedeki özelliği açıp kapatmak için kullanılan bağlama söz dizimidirinputRef.toggleAttribute('attribute-name', booleanVar)
etiketine eşdeğerinputElement.hasAttribute('disabled') === true
nedeniyle,disabled="false"
olarakdisabled
kullanan öğeler DOM tarafından doğru olarak okunmaya devam eder.
html`<my-element .property-name=${anyVar}>`;
.
öneki, bir öğenin özelliğini ayarlamak için kullanılan bağlama söz dizimidirinputRef.propertyName = anyVar
etiketine eşdeğer- Nesneler, diziler veya sınıflar gibi karmaşık verileri iletmek için idealdir
html`<my-element attribute-name=${stringVar}>`;
- Bir öğenin özelliğine bağlanır
inputRef.setAttribute('attribute-name', stringVar)
etiketine eşdeğer- Temel değerler, stil kuralı seçiciler ve querySelector için uygundur
Geçiş işleyiciler
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element =
<input
onClick={() => console.log('click')}
onChange={e => console.log(e.target.value)} />;
ReactDOM.render(
element,
mountNode
);
Yukarıdaki örnekte, aşağıdakileri yapan bir giriş tanımlanır:
- "click" kelimesini günlüğe kaydet giriş tıklandığında
- Kullanıcı bir karakter yazdığında giriş değerini günlüğe kaydet
Edebiyat'ta şunları yaparsınız:
import {html, render} from 'lit';
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element = html`
<input
@click=${() => console.log('click')}
@input=${e => console.log(e.target.value)}>`;
render(
element,
mountNode
);
Edebiyat örneğinde, @click
ile click
etkinliğine eklenmiş bir işleyici vardır.
Ardından, yerel change
etkinliği yalnızca blur
tarihinde etkinleştiğinden (soyutları bu etkinlikler üzerinden tepki ver) onChange
kullanmak yerine <input>
etkinliğinin yerel input
etkinliği için bir bağlantı bulunur.
Lit etkinlik işleyici söz dizimi
html`<my-element @event-name=${() => {...}}></my-element>`;
@
öneki, etkinlik işleyici için bağlama söz dizimidirinputRef.addEventListener('event-name', ...)
etiketine eşdeğer- Yerel DOM etkinlik adlarını kullanır
5. Bileşenler ve Dekorlar
Bu bölümde edebiyat sınıfı bileşenleri ve işlevleri hakkında bilgi edineceksiniz. Durum ve Kancalar sonraki bölümlerde daha ayrıntılı olarak ele alınacaktır.
Sınıf Bileşenleri ve LitElement
React sınıfı bileşeninin Lit eşdeğeri, LitElement ve Lit'in "reaktif özellikler" kavramıdır React'in özellikleri ve durumunun birleşimidir. Örneğin:
import React from 'react';
import ReactDOM from 'react-dom';
class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {name: ''};
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
const element = <Welcome name="Elliott"/>
ReactDOM.render(
element,
mountNode
);
Yukarıdaki örnekte şu özelliklere sahip bir React bileşeni vardır:
name
oluşturur- Varsayılan
name
değerini boş dize (""
) olarak ayarlar name
adlı kişiyi"Elliott"
adlı kullanıcıya yeniden atar
LitElement'te bu işlemi şu şekilde yaparsınız:
TypeScript'te:
import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
@property({type: String})
name = '';
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
}
JavaScript'te:
import {LitElement, html} from 'lit';
class WelcomeBanner extends LitElement {
static get properties() {
return {
name: {type: String}
}
}
constructor() {
super();
this.name = '';
}
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
}
customElements.define('welcome-banner', WelcomeBanner);
Ayrıca HTML dosyasında:
<!-- index.html -->
<head>
<script type="module" src="./index.js"></script>
</head>
<body>
<welcome-banner name="Elliott"></welcome-banner>
</body>
Yukarıdaki örnekte neler olduğuna ilişkin bir inceleme:
@property({type: String})
name = '';
- Bileşeninizin herkese açık API'sinin bir parçası olan herkese açık reaktif bir özelliği tanımlar
- Bileşeninizde bir özelliğin (varsayılan olarak) yanı sıra bir özelliği sunar
- Bileşenin özelliğinin (dize olan) bir değere nasıl çevrileceğini tanımlar
static get properties() {
return {
name: {type: String}
}
}
- Bu,
@property
TS tasarımcısıyla aynı işlevi görür ancak JavaScript'te yerel olarak çalışır
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
- Bu, herhangi bir reaktif özellik değiştirildiğinde çağrılır
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
...
}
- Bu, bir HTML Öğesi etiketi adını sınıf tanımıyla ilişkilendirir
- Özel Öğeler standardı nedeniyle, etiket adı kısa çizgi (-) içermelidir olmalıdır
- LitElement içindeki
this
, özel öğe örneğini ifade eder (bu örnekte<welcome-banner>
)
customElements.define('welcome-banner', WelcomeBanner);
- Bu,
@customElement
TS tasarımcısının JavaScript eşdeğeridir
<head>
<script type="module" src="./index.js"></script>
</head>
- Özel öğe tanımını içe aktarır
<body>
<welcome-banner name="Elliott"></welcome-banner>
</body>
- Özel öğeyi sayfaya ekler
name
özelliğini'Elliott'
olarak ayarlar
İşlev Bileşenleri
Edebiyatta JSX veya ön işlemci kullanılmadığı için bir işlev bileşeni 1:1 yoruma sahip değildir. Bununla birlikte, özellikleri alan ve DOM'yi bu özelliklere dayanarak oluşturan bir işlev oluşturmak oldukça basittir. Örneğin:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Elliott"/>
ReactDOM.render(
element,
mountNode
);
Özetle bu şu şekilde olacaktır:
import {html, render} from 'lit';
function Welcome(props) {
return html`<h1>Hello, ${props.name}</h1>`;
}
render(
Welcome({name: 'Elliott'}),
document.body.querySelector('#root')
);
6. Eyalet & Yaşam döngüsü
Bu bölümde Lit'in durumu ve yaşam döngüsü hakkında bilgi edineceksiniz.
Eyalet
Lit'in "Reaktif Özellikler" kavramı React'in durumu ve sahne unsurlarının bir karışımıdır. Reaktif Özellikler, değiştirildiğinde bileşenin yaşam döngüsünü tetikleyebilir. Reaktif özelliklerin iki varyantı vardır:
Herkese açık reaktif mülkler
// React
import React from 'react';
class MyEl extends React.Component {
constructor(props) {
super(props)
this.state = {name: 'there'}
}
componentWillReceiveProps(nextProps) {
if (this.props.name !== nextProps.name) {
this.setState({name: nextProps.name})
}
}
}
// Lit (TS)
import {LitElement} from 'lit';
import {property} from 'lit/decorators.js';
class MyEl extends LitElement {
@property() name = 'there';
}
- Tanımlayan:
@property
- React'in özellikleri ve durumuna benzer ama değişebilir
- Bileşenin tüketicileri tarafından erişilen ve ayarlanan herkese açık API
Dahili reaktif durum
// React
import React from 'react';
class MyEl extends React.Component {
constructor(props) {
super(props)
this.state = {name: 'there'}
}
}
// Lit (TS)
import {LitElement} from 'lit';
import {state} from 'lit/decorators.js';
class MyEl extends LitElement {
@state() name = 'there';
}
- Tanımlayan:
@state
- React'in durumuna benzer ancak değişebilir
- Genellikle bileşen veya alt sınıfların içinden erişilen dahili gizli durum
Yaşam döngüsü
Lit yaşam döngüsü React'in yaşam döngüsüne oldukça benzer ancak önemli bazı farklılıklar vardır.
constructor
// React (js)
import React from 'react';
class MyEl extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this._privateProp = 'private';
}
}
// Lit (ts)
class MyEl extends LitElement {
@property({type: Number}) counter = 0;
private _privateProp = 'private';
}
// Lit (js)
class MyEl extends LitElement {
static get properties() {
return { counter: {type: Number} }
}
constructor() {
this.counter = 0;
this._privateProp = 'private';
}
}
- Litrenin eşdeğeri de
constructor
- Süper çağrıya herhangi bir bilgi iletmeye gerek yoktur.
- Çağrı yapan (tamamen kapsayıcı değil):
document.createElement
document.innerHTML
new ComponentClass()
- Sayfada yeni sürüme geçirilmemiş bir etiket adı varsa ve tanım yüklenip
@customElement
veyacustomElements.define
ile kaydedilmişse
- İşlev olarak React'in
constructor
işlevine benzer
render
// React
render() {
return <div>Hello World</div>
}
// Lit
render() {
return html`<div>Hello World</div>`;
}
- Litrenin eşdeğeri de
render
- Oluşturulabilir herhangi bir sonucu döndürebilir, ör.
TemplateResult
veyastring
vb. - React'e benzer şekilde,
render()
yalın bir işlev olmalıdır createRenderRoot()
tarafından döndürülen düğümde oluşturulur (varsayılan olarakShadowRoot
)
componentDidMount
componentDidMount
, Lit'in firstUpdated
ve connectedCallback
yaşam döngüsü geri çağırmalarının kombinasyonuna benzer.
firstUpdated
import Chart from 'chart.js';
// React
componentDidMount() {
this._chart = new Chart(this.chartElRef.current, {...});
}
// Lit
firstUpdated() {
this._chart = new Chart(this.chartEl, {...});
}
- Bileşenin şablonu bileşenin kökünde ilk kez oluşturulduğunda çağrılır
- Yalnızca öğe bağlıysa çağrılır (ör. bu düğüm DOM ağacına eklenene kadar
document.createElement('my-component')
aracılığıyla çağrılmaz - Burası, bileşen tarafından oluşturulan DOM'nin kullanılmasını gerektiren bileşen kurulumunu yapmak için iyi bir yerdir
- React'in
firstUpdated
içindeki reaktif özelliklerde yapılancomponentDidMount
değişikliklerinin aksine, bu değişiklikler yeniden işlemeye neden olur ancak tarayıcı genellikle değişiklikleri aynı çerçevede toplu hale getirir. Bu değişiklikler, kökün DOM'sine erişim gerektirmiyorsa genelliklewillUpdate
içinde yapılması gerekir.
connectedCallback
// React
componentDidMount() {
this.window.addEventListener('resize', this.boundOnResize);
}
// Lit
connectedCallback() {
super.connectedCallback();
this.window.addEventListener('resize', this.boundOnResize);
}
- Özel öğe DOM ağacına her eklendiğinde çağrılır
- React bileşenlerinin aksine, DOM'den çıkarılan özel öğeler yok edilmez ve böylece "bağlanabilir" olabilir. birden çok kez
firstUpdated
tekrar çağrılmayacak
- DOM'yi yeniden başlatmak veya bağlantı kesildiğinde temizlenen etkinlik işleyicileri yeniden eklemek için kullanışlıdır
- Not:
connectedCallback
,firstUpdated
tarihinden önce çağrılabilir. Bu nedenle, ilk görüşmede DOM kullanılamayabilir.
componentDidUpdate
// React
componentDidUpdate(prevProps) {
if (this.props.title !== prevProps.title) {
this._chart.setTitle(this.props.title);
}
}
// Lit (ts)
updated(prevProps: PropertyValues<this>) {
if (prevProps.has('title')) {
this._chart.setTitle(this.title);
}
}
- Edebiyat eşdeğeri
updated
("update"in İngilizce son zamanı kullanılır) - React'in aksine
updated
, ilk oluşturma sırasında da çağrılır - İşlev olarak React'in
componentDidUpdate
işlevine benzer
componentWillUnmount
// React
componentWillUnmount() {
this.window.removeEventListener('resize', this.boundOnResize);
}
// Lit
disconnectedCallback() {
super.disconnectedCallback();
this.window.removeEventListener('resize', this.boundOnResize);
}
- Edebiyat eşdeğeri,
disconnectedCallback
ile benzer - React bileşenlerinin aksine, özel öğeler DOM'den çıkarıldığında bileşen kaldırılmaz
componentWillUnmount
işlevinin aksinedisconnectedCallback
, öğe ağaçtan kaldırıldıktan sonra çağrılır- Kök içindeki DOM, kökün alt ağacına hâlâ bağlı
- Tarayıcının, bileşeni çöplerini toplayabilmesi için etkinlik işleyicileri ve sızdıran referansları temizlemek amacıyla kullanışlıdır
Antrenman
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Yukarıdaki örnekte, aşağıdakileri yapan basit bir saat vardır:
- "Hello World! Öyle" ve saatin kaç olduğunu
- Her saniyede saat güncellenir
- Ayrıldığında, işareti çağıran aralığı temizler
Öncelikle bileşen sınıf bildirimiyle başlayın:
// Lit (TS)
// some imports here are imported in advance
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';
@customElement('lit-clock')
class LitClock extends LitElement {
}
// Lit (JS)
// `html` is imported in advance
import {LitElement, html} from 'lit';
class LitClock extends LitElement {
}
customElements.define('lit-clock', LitClock);
Daha sonra, bileşenin kullanıcıları date
öğesini doğrudan ayarlayamayacağı için date
öğesini başlatın ve @state
ile dahili reaktif özellik olarak bildirin.
// Lit (TS)
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';
@customElement('lit-clock')
class LitClock extends LitElement {
@state() // declares internal reactive prop
private date = new Date(); // initialization
}
// Lit (JS)
import {LitElement, html} from 'lit';
class LitClock extends LitElement {
static get properties() {
return {
// declares internal reactive prop
date: {state: true}
}
}
constructor() {
super();
// initialization
this.date = new Date();
}
}
customElements.define('lit-clock', LitClock);
Daha sonra, şablonu oluşturun.
// Lit (JS & TS)
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
Şimdi de tick yöntemini uygulayın.
tick() {
this.date = new Date();
}
Ardından, componentDidMount
uygulanmasına geçilir. Tekrarlamak gerekirse, Lit analog'u firstUpdated
ve connectedCallback
'nın bir karışımıdır. Bu bileşende, setInterval
ile tick
çağrısı yapmak kök içindeki DOM'ye erişim gerektirmez. Ayrıca, öğe doküman ağacından kaldırıldığında aralık temizlenir. Dolayısıyla, öğe yeniden eklenirse aralığın yeniden başlaması gerekir. Bu nedenle connectedCallback
burada daha iyi bir seçimdir.
// Lit (TS)
@customElement('lit-clock')
class LitClock extends LitElement {
@state()
private date = new Date();
// initialize timerId for TS
private timerId = -1 as unknown as ReturnType<typeof setTimeout>;
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
...
}
// Lit (JS)
constructor() {
super();
// initialization
this.date = new Date();
this.timerId = -1; // initialize timerId for JS
}
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
Son olarak, öğenin belge ağacından bağlantısı kesildikten sonra onay işaretinin yürütülmemesi için aralığı temizleyin.
// Lit (TS & JS)
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
Hepsini bir araya getirdiğimizde şu şekilde görünmelidir:
// Lit (TS)
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';
@customElement('lit-clock')
class LitClock extends LitElement {
@state()
private date = new Date();
private timerId = -1 as unknown as ReturnType<typeof setTimeout>;
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
tick() {
this.date = new Date();
}
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
}
// Lit (JS)
import {LitElement, html} from 'lit';
class LitClock extends LitElement {
static get properties() {
return {
date: {state: true}
}
}
constructor() {
super();
this.date = new Date();
}
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
tick() {
this.date = new Date();
}
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
}
customElements.define('lit-clock', LitClock);
7. Kancalar
Bu bölümde React Hook kavramlarını Edebiyat'a nasıl çevireceğinizi öğreneceksiniz.
React kancaları kavramları
Tepki kancaları, işlev bileşenlerinin "çengellenmesi" için bir yol sağlar içine alır. Bunun birkaç avantajı vardır.
- Durum bilgili mantığın yeniden kullanımını basitleştirir
- Bir bileşenin daha küçük işlevlere bölünmesine yardımcı olun
Ek olarak, işlev tabanlı bileşenlere odaklanma, React'in sınıfa dayalı söz dizimiyle ilgili şu gibi sorunları ele aldı:
props
adlı kişininconstructor
-super
arasında geçmesi gerekiyorconstructor
- içindeki özelliklerin düzenli şekilde başlatılması
- Bu, o zamanlar React ekibi tarafından belirtilmiş ancak ES2019 tarafından çözülen bir nedendi
this
nedeniyle ortaya çıkan sorunlar artık bileşene atıfta bulunmuyor
Edebiyat'taki tepki kancası kavramları
Bileşenler ve Dekorlar bölümünde Lit, bir işlevden özel öğe oluşturmak için bir yöntem sunmaz, ancak LitElement, React sınıf bileşenleriyle ilgili temel sorunların çoğunu ele alır. Örneğin:
// React (at the time of making hooks)
import React from 'react';
import ReactDOM from 'react-dom';
class MyEl extends React.Component {
constructor(props) {
super(props); // Leaky implementation
this.state = {count: 0};
this._chart = null; // Deemed messy
}
render() {
return (
<>
<div>Num times clicked {count}</div>
<button onClick={this.clickCallback}>click me</button>
</>
);
}
clickCallback() {
// Errors because `this` no longer refers to the component
this.setState({count: this.count + 1});
}
}
// Lit (ts)
class MyEl extends LitElement {
@property({type: Number}) count = 0; // No need for constructor to set state
private _chart = null; // Public class fields introduced to JS in 2019
render() {
return html`
<div>Num times clicked ${count}</div>
<button @click=${this.clickCallback}>click me</button>`;
}
private clickCallback() {
// No error because `this` refers to component
this.count++;
}
}
Lit bu sorunları nasıl ele alır?
constructor
, bağımsız değişken kabul etmez@event
bağlamanın tümüthis
öğesine otomatik olarak bağlanıyor- Vakaların büyük çoğunluğunda
this
, özel öğenin referansıyla ilgilidir - Sınıf özellikleri artık sınıf üyeleri olarak örneklenebilir. Bu, kurucu tabanlı uygulamaları temizler
Reaktif Kumandalar
Hooks'un temel kavramları, Lit'te reaktif denetleyiciler olarak bulunur. Reaktif denetleyici kalıpları, durum bilgili mantığın paylaşılmasına, bileşenlerin daha küçük ve daha modüler bitlere bölünmesine ve bir öğenin güncelleme yaşam döngüsüne bağlanmasına olanak tanır.
Reaktif denetleyici, LitElement gibi bir denetleyici ana makinesinin güncelleme yaşam döngüsüne bağlanabilen bir nesne arayüzüdür.
ReactiveController
ve reactiveControllerHost
yaşam döngüsü şu şekildedir:
interface ReactiveController {
hostConnected(): void;
hostUpdate(): void;
hostUpdated(): void;
hostDisconnected(): void;
}
interface ReactiveControllerHost {
addController(controller: ReactiveController): void;
removeController(controller: ReactiveController): void;
requestUpdate(): void;
readonly updateComplete: Promise<boolean>;
}
Reaktif bir denetleyici oluşturup addController
ile bir ana makineye ekleyerek denetleyicinin yaşam döngüsü, ana makinenin yaşam döngüsüyle birlikte çağrılır. Örneğin, Eyalet & Yaşam döngüsü bölümü:
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Yukarıdaki örnekte, aşağıdakileri yapan basit bir saat vardır:
- "Hello World! Öyle" ve saatin kaç olduğunu
- Her saniyede saat güncellenir
- Ayrıldığında, işareti çağıran aralığı temizler
Bileşen iskelesinin oluşturulması
Öncelikle bileşen sınıf bildirimiyle başlayın ve render
işlevini ekleyin.
// Lit (TS) - index.ts
import {LitElement, html} from 'lit';
import {customElement} from 'lit/decorators.js';
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${'time to get Lit'}.</h2>
</div>
`;
}
}
// Lit (JS) - index.js
import {LitElement, html} from 'lit';
class MyElement extends LitElement {
render() {
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${'time to get Lit'}.</h2>
</div>
`;
}
}
customElements.define('my-element', MyElement);
Denetleyiciyi oluşturma
Şimdi clock.ts
ürününe geçin, ClockController
için bir sınıf oluşturun ve constructor
ayarını yapın:
// Lit (TS) - clock.ts
import {ReactiveController, ReactiveControllerHost} from 'lit';
export class ClockController implements ReactiveController {
private readonly host: ReactiveControllerHost;
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
hostConnected() {
}
private tick() {
}
hostDisconnected() {
}
}
// Lit (JS) - clock.js
export class ClockController {
constructor(host) {
this.host = host;
host.addController(this);
}
hostConnected() {
}
tick() {
}
hostDisconnected() {
}
}
ReactiveController
arayüzünü paylaştığı sürece reaktif bir denetleyici herhangi bir şekilde oluşturulabilir. Ancak hem ReactiveControllerHost
arayüzünde yer alabilecek constructor
öğesine sahip bir sınıfın hem de denetleyiciyi başlatmak için gereken diğer tüm özelliklerin kullanılması, Lit ekibinin çoğu temel durumda kullanmayı tercih ettiği bir kalıptır.
Şimdi React yaşam döngüsü geri çağırmalarını denetleyici geri çağırmalarına çevirmeniz gerekiyor. Kısaca:
componentDidMount
- LitElement'ın
connectedCallback
cihazına - Kumandanın
hostConnected
cihazına
- LitElement'ın
ComponentWillUnmount
- LitElement'ın
disconnectedCallback
cihazına - Kumandanın
hostDisconnected
cihazına
- LitElement'ın
React yaşam döngüsünü Lit yaşam döngüsüne çevirme hakkında daha fazla bilgi için bkz. Durum ve Yaşam döngüsü bölümünü inceleyin.
Ardından, hostConnected
geri çağırmasını ve tick
yöntemlerini uygulayın ve hostDisconnected
aralığındaki aralığı temizleyin. Boşlukları Durum ve Yaşam döngüsü bölümünü inceleyin.
// Lit (TS) - clock.ts
export class ClockController implements ReactiveController {
private readonly host: ReactiveControllerHost;
private interval = 0 as unknown as ReturnType<typeof setTimeout>;
date = new Date();
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
hostConnected() {
this.interval = setInterval(() => this.tick(), 1000);
}
private tick() {
this.date = new Date();
}
hostDisconnected() {
clearInterval(this.interval);
}
}
// Lit (JS) - clock.js
export class ClockController {
interval = 0;
host;
date = new Date();
constructor(host) {
this.host = host;
host.addController(this);
}
hostConnected() {
this.interval = setInterval(() => this.tick(), 1000);
}
tick() {
this.date = new Date();
}
hostDisconnected() {
clearInterval(this.interval);
}
}
Denetleyiciyi kullanma
Saat denetleyicisini kullanmak için kumandayı içe aktarın ve bileşeni index.ts
veya index.js
ürününde güncelleyin.
// Lit (TS) - index.ts
import {LitElement, html, ReactiveController, ReactiveControllerHost} from 'lit';
import {customElement} from 'lit/decorators.js';
import {ClockController} from './clock.js';
@customElement('my-element')
class MyElement extends LitElement {
private readonly clock = new ClockController(this); // Instantiate
render() {
// Use controller
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${this.clock.date.toLocaleTimeString()}.</h2>
</div>
`;
}
}
// Lit (JS) - index.js
import {LitElement, html} from 'lit';
import {ClockController} from './clock.js';
class MyElement extends LitElement {
clock = new ClockController(this); // Instantiate
render() {
// Use controller
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${this.clock.date.toLocaleTimeString()}.</h2>
</div>
`;
}
}
customElements.define('my-element', MyElement);
Denetleyiciyi kullanmak için denetleyici ana makinesine (<my-element>
bileşenidir) bir referans ileterek denetleyiciyi örneklendirmeniz ve ardından denetleyiciyi render
yönteminde kullanmanız gerekir.
Denetleyicide yeniden oluşturmayı tetikleme
Saatin gösterildiğinden, ancak saatin güncellenmediğini unutmayın. Bunun nedeni denetleyicinin her saniyede bir tarih ayarlamasına rağmen ana makinenin güncelleme yapmamasıdır. Bunun nedeni, date
öğesinin artık ClockController
sınıfında değişmesi, bileşenin bundan sonra değişmemesidir. Bu nedenle, date
, denetleyicide ayarlandıktan sonra ana makineye güncelleme yaşam döngüsünü host.requestUpdate()
ile çalıştırması söylenmelidir.
// Lit (TS & JS) - clock.ts / clock.js
private tick() {
this.date = new Date();
this.host.requestUpdate();
}
Zaman azalıyor!
Kancaların kullanıldığı yaygın kullanım alanlarının daha ayrıntılı bir karşılaştırması için lütfen Gelişmiş Konular - Kancalar bölümüne bakın.
8. Çocuklar
Bu bölümde Edebiyat'ta alt öğeleri yönetmek için slotları nasıl kullanacağınızı öğreneceksiniz.
Yuvalar ve Çocuklar
Slotlar, bileşenleri iç içe yerleştirmenize olanak tanıyarak bestelemenize olanak tanır.
React'te çocuklar eşyalardan kalıtılır. Varsayılan alan props.children
, render
işlevi ise varsayılan alanın konumlandırıldığı yeri tanımlar. Örneğin:
const MyArticle = (props) => {
return <article>{props.children}</article>;
};
props.children
öğelerinin HTML öğeleri değil, React Bileşenleri olduğunu unutmayın.
Edebiyat'ta alt öğeler, oluşturma işlevinde slot öğeleriyle oluşturulur. Alt öğelerin React ile aynı şekilde devralınmadığına dikkat edin. Lit'te alt öğeler, alanlara eklenmiş HTMLElement'lardır. Bu eke Projeksiyon adı verilir.
@customElement("my-article")
export class MyArticle extends LitElement {
render() {
return html`
<article>
<slot></slot>
</article>
`;
}
}
Birden Çok Yuva
React'te birden fazla slot eklemek, temelde daha fazla öğe devralmayla aynıdır.
const MyArticle = (props) => {
return (
<article>
<header>
{props.headerChildren}
</header>
<section>
{props.sectionChildren}
</section>
</article>
);
};
Benzer şekilde, daha fazla <slot>
öğesi eklendiğinde Edebiyat'ta daha fazla alan oluşturulur. Birden fazla alan, name
özelliğiyle tanımlanır: <slot name="slot-name">
. Bu, çocukların hangi alana atanacaklarını bildirmelerine olanak tanır.
@customElement("my-article")
export class MyArticle extends LitElement {
render() {
return html`
<article>
<header>
<slot name="headerChildren"></slot>
</header>
<section>
<slot name="sectionChildren"></slot>
</section>
</article>
`;
}
}
Varsayılan Alan İçeriği
Slotlar, bu alana yansıtılan düğüm olmadığında alt ağaçlarını gösterir. Düğümler bir yuvaya yansıtıldığında, bu alan alt ağacını göstermez ve bunun yerine yansıtılan düğümleri gösterir.
@customElement("my-element")
export class MyElement extends LitElement {
render() {
return html`
<section>
<div>
<slot name="slotWithDefault">
<p>
This message will not be rendered when children are attached to this slot!
<p>
</slot>
</div>
</section>
`;
}
}
Alanlara alt öğe atama
React'te alt öğeler, bir bileşenin özellikleri aracılığıyla alanlara atanır. Aşağıdaki örnekte React öğeleri, headerChildren
ve sectionChildren
özelliklerine iletilir.
const MyNewsArticle = () => {
return (
<MyArticle
headerChildren={<h3>Extry, Extry! Read all about it!</h3>}
sectionChildren={<p>Children are props in React!</p>}
/>
);
};
Edebiyat'ta, alt alanlara slot
özelliği kullanılarak atanır.
@customElement("my-news-article")
export class MyNewsArticle extends LitElement {
render() {
return html`
<my-article>
<h3 slot="headerChildren">
Extry, Extry! Read all about it!
</h3>
<p slot="sectionChildren">
Children are composed with slots in Lit!
</p>
</my-article>
`;
}
}
Varsayılan alan (ör. <slot>
) yoksa ve özel öğenin alt öğelerinin slot
özelliğiyle (ör. <div slot="foo">
) eşleşen name
özelliğine sahip bir alan (ör. <slot name="foo">
) yoksa bu düğüm yansıtılmaz ve gösterilmez.
9. Ref
Zaman zaman geliştiricinin HTMLElement API'sine erişmesi gerekebilir.
Bu bölümde Edebiyat'ta öğe referanslarını nasıl edineceğinizi öğreneceksiniz.
React referansları
React bileşeni, çağrıldığında sanal DOM oluşturan bir dizi işlev çağrısına aktarılır. Bu sanal DOM, ReactDOM tarafından yorumlanır ve HTMLElements oluşturur.
React'te Ref'ler, oluşturulmuş bir HTMLElement'ı içerecek şekilde bellekteki alandır.
const RefsExample = (props) => {
const inputRef = React.useRef(null);
const onButtonClick = React.useCallback(() => {
inputRef.current?.focus();
}, [inputRef]);
return (
<div>
<input type={"text"} ref={inputRef} />
<br />
<button onClick={onButtonClick}>
Click to focus on the input above!
</button>
</div>
);
};
Yukarıdaki örnekte Tepki bileşeni aşağıdaki işlemleri yapar:
- Boş bir metin girişi ve metin içeren bir düğme oluştur
- Düğme tıklandığında girişe odaklanır
İlk oluşturma işleminden sonra React, ref
özelliği aracılığıyla oluşturulan HTMLInputElement
değerine inputRef.current
değerini ayarlar.
Lit "Referanslar" @query
ile birlikte
Lit, tarayıcıya yakın bir yerde bulunur ve yerel tarayıcı özellikleri üzerinde çok ince bir soyutlama oluşturur.
Edebiyat'taki refs
ifadesine karşılık gelen Tepki, @query
ve @queryAll
tasarımcıları tarafından döndürülen HTMLElement öğesidir.
@customElement("my-element")
export class MyElement extends LitElement {
@query('input') // Define the query
inputEl!: HTMLInputElement; // Declare the prop
// Declare the click event listener
onButtonClick() {
// Use the query to focus
this.inputEl.focus();
}
render() {
return html`
<input type="text">
<br />
<!-- Bind the click listener -->
<button @click=${this.onButtonClick}>
Click to focus on the input above!
</button>
`;
}
}
Yukarıdaki örnekte, Lit bileşeni şunları yapar:
@query
tasarımcısını kullanarakMyElement
üzerinde bir özellik tanımlar (HTMLInputElement
için alıcı oluşturuluyor).onButtonClick
adlı bir tıklama etkinliği geri çağırması bildirir ve ekler.- Düğme tıklandığında girişe odaklanır
JavaScript'te, @query
ve @queryAll
tasarımcıları sırasıyla querySelector
ve querySelectorAll
işlemlerini gerçekleştirir. Bu, @query('input') inputEl!: HTMLInputElement;
işlevinin JavaScript eşdeğeridir
get inputEl() {
return this.renderRoot.querySelector('input');
}
Lit bileşeni, render
yönteminin şablonunu my-element
köküne kaydettikten sonra, @query
tasarımcısı artık inputEl
ürününün, oluşturma kökünde bulunan ilk input
öğesini döndürmesine izin verir. @query
belirtilen öğeyi bulamazsa null
değerini döndürür.
Oluşturma kökünde birden fazla input
öğesi varsa @queryAll
bir düğüm listesi döndürür.
10. Arabuluculuk Durumu
Bu bölümde, Edebiyat'ta bileşenler arasında durum uyumlulaştırmasından nasıl yararlanacağınızı öğreneceksiniz.
Yeniden Kullanılabilir Bileşenler
React, yukarıdan aşağıya veri akışı olan işlevsel oluşturma ardışık düzenlerini taklit eder. Ebeveynler, eşyalar aracılığıyla çocuklara durum bilgisi verirler. Çocuklar, öğelerdeki geri aramaları kullanarak ebeveynleriyle iletişim kurar.
const CounterButton = (props) => {
const label = props.step < 0
? `- ${-1 * props.step}`
: `+ ${props.step}`;
return (
<button
onClick={() =>
props.addToCounter(props.step)}>{label}</button>
);
};
Yukarıdaki örnekte, bir React bileşeni şunları yapar:
props.step
değerine göre bir etiket oluşturur.- Etiketi +adım veya -adım olan bir düğme oluşturur
- Tıklamada bağımsız değişken olarak
props.step
ileprops.addToCounter
çağrısı yaparak üst bileşeni günceller
Edebiyat'ta geri çağırmaları aktarmak mümkün olsa da geleneksel kalıplar farklıdır. Yukarıdaki örnekteki React Bileşeni, aşağıdaki örnekte Edebiyat Bileşeni olarak yazılabilir:
@customElement('counter-button')
export class CounterButton extends LitElement {
@property({type: Number}) step: number = 0;
onClick() {
const event = new CustomEvent('update-counter', {
bubbles: true,
detail: {
step: this.step,
}
});
this.dispatchEvent(event);
}
render() {
const label = this.step < 0
? `- ${-1 * this.step}` // "- 1"
: `+ ${this.step}`; // "+ 1"
return html`
<button @click=${this.onClick}>${label}</button>
`;
}
}
Yukarıdaki örnekte, Lit Bileşeni şunları yapacak:
step
reaktif özelliğini oluştur- Tıklandığında öğenin
step
değerini taşıyanupdate-counter
adlı bir özel etkinlik gönderin
Tarayıcı etkinlikleri, alt öğelerden üst öğelere çıkar. Etkinlikler, çocukların etkileşim etkinliklerini ve durum değişikliklerini yayınlamasına olanak tanır. Tepki, temel olarak ters yönde bir durum geçer. Bu nedenle, React Bileşenlerinin dağıtıldığını görmek ve etkinlikleri, Lit Bileşenleriyle aynı şekilde dinlemek alışılmadık bir durumdur.
Durum Bilgili Bileşenler
React'te durumu yönetmek için kancalar yaygın olarak kullanılır. CounterButton
Bileşeni yeniden kullanılarak bir MyCounter
Bileşeni oluşturulabilir. addToCounter
öğesinin her iki CounterButton
örneğine nasıl iletildiğine dikkat edin.
const MyCounter = (props) => {
const [counterSum, setCounterSum] = React.useState(0);
const addToCounter = useCallback(
(step) => {
setCounterSum(counterSum + step);
},
[counterSum, setCounterSum]
);
return (
<div>
<h3>Σ: {counterSum}</h3>
<CounterButton
step={-1}
addToCounter={addToCounter} />
<CounterButton
step={1}
addToCounter={addToCounter} />
</div>
);
};
Yukarıdaki örnekte aşağıdaki işlemler gerçekleşir:
count
durumu oluşturur.count
durumuna numara ekleyen bir geri arama oluşturur.CounterButton
, her tıklamadacount
uygulamasınıstep
tarihine kadar güncellemek içinaddToCounter
kullanır.
Benzer bir MyCounter
uygulaması Edebiyat'ta da gerçekleştirilebilir. addToCounter
öğesinin counter-button
öğesine nasıl aktarılmadığına dikkat edin. Bunun yerine, geri çağırma bir üst öğedeki @update-counter
etkinliğine etkinlik işleyici olarak bağlanır.
@customElement("my-counter")
export class MyCounter extends LitElement {
@property({type: Number}) count = 0;
addToCounter(e: CustomEvent<{step: number}>) {
// Get step from detail of event or via @query
this.count += e.detail.step;
}
render() {
return html`
<div @update-counter="${this.addToCounter}">
<h3>Σ ${this.count}</h3>
<counter-button step="-1"></counter-button>
<counter-button step="1"></counter-button>
</div>
`;
}
}
Yukarıdaki örnekte aşağıdaki işlemler gerçekleşir:
- Değer değiştirildiğinde bileşeni güncelleyecek
count
adlı reaktif bir özellik oluşturur. addToCounter
geri çağırmasını@update-counter
etkinlik işleyiciye bağlarcount
adlı etkinliği,update-counter
etkinliğinindetail.step
. kısmındaki değeri ekleyerek güncellercounter-button
öğesininstep
değerini,step
özelliği aracılığıyla ayarlar
Ebeveynlerden çocuklara yapılan değişiklikleri yayınlamak için Lit'te reaktif özelliklerin kullanılması daha geleneksel bir yaklaşımdır. Aynı şekilde, ayrıntıları aşağıdan yukarı doğru baloncuk oluşturmak için tarayıcının etkinlik sistemini kullanmak iyi bir uygulamadır.
Bu yaklaşım, en iyi uygulamaları izler ve Lit'in web bileşenleri için platformlar arası destek sağlama hedefine uygundur.
11. Stil
Bu bölümde Edebiyat'ta stil hakkında bilgi edineceksiniz.
Stil
Edebiyat, öğeleri biçimlendirmek için çeşitli yöntemler ve yerleşik bir çözüm sunuyor.
Satır İçi Stiller
Edebiyat, satır içi stilleri ve bunlara bağlamayı destekler.
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
<div>
<h1 style="color:orange;">This text is orange</h1>
<h1 style="color:rebeccapurple;">This text is rebeccapurple</h1>
</div>
`;
}
}
Yukarıdaki örnekte her biri satır içi stile sahip 2 başlık vardır.
Şimdi bir kenarlığı içe aktarıp border-color.js
ile turuncu metne bağlayın:
...
import borderColor from './border-color.js';
...
html`
...
<h1 style="color:orange;${borderColor}">This text is orange</h1>
...`
Stil dizesini her seferinde hesaplamak biraz sinir bozucu olabilir. Bu nedenle Lit bu konuda yardımcı olacak bir yönerge sunuyor.
styleMap
styleMap
yönergesi, satır içi stilleri ayarlamak için JavaScript'in kullanılmasını kolaylaştırır. Örneğin:
import {LitElement, html, css} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {styleMap} from 'lit/directives/style-map.js';
@customElement('my-element')
class MyElement extends LitElement {
@property({type: String})
color = '#000'
render() {
// Define the styleMap
const headerStyle = styleMap({
'border-color': this.color,
});
return html`
<div>
<h1
style="border-style:solid;
<!-- Use the styleMap -->
border-width:2px;${headerStyle}">
This div has a border color of ${this.color}
</h1>
<input
type="color"
@input=${e => (this.color = e.target.value)}
value="#000">
</div>
`;
}
}
Yukarıdaki örnek şunları sağlar:
- Kenarlık ve renk seçici içeren bir
h1
görüntüler border-color
değerini, renk seçicideki değerle değiştirir
Buna ek olarak, h1
stilini ayarlamak için kullanılan styleMap
bulunur. styleMap
, React'in style
özellik bağlama söz dizimine benzer bir söz dizimi uygular.
CSSResult
Bileşenlerin stilini belirlemek için önerilen yol, css
etiketli düz şablon kullanmaktır.
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';
const ORANGE = css`orange`;
@customElement('my-element')
class MyElement extends LitElement {
static styles = [
css`
#orange {
color: ${ORANGE};
}
#purple {
color: rebeccapurple;
}
`
];
render() {
return html`
<div>
<h1 id="orange">This text is orange</h1>
<h1 id="purple">This text is rebeccapurple</h1>
</div>
`;
}
}
Yukarıdaki örnek şunları sağlar:
- Bağlama sahip bir CSS etiketli şablon sabit değerini tanımlar
- Kimlik içeren iki
h1
öğesinin renklerini ayarlar
css
şablon etiketini kullanmanın avantajları:
- Sınıf başına ve örnek başına bir kez ayrıştırılır
- Modülün yeniden kullanılabilirliği göz önünde bulundurularak uygulandı
- Stilleri kolayca kendi dosyalarına ayırabilir
- CSS Özel Özellikler çoklu dolgusu ile uyumlu
Ayrıca index.html
içindeki <style>
etiketine dikkat edin:
<!-- index.html -->
<style>
h1 {
color: red !important;
}
</style>
Proje, bileşenlerinizin kapsamını belirler köklerine kadar uzanıyor. Bu, stillerin içeri girip çıkmayacağı anlamına gelir. Edebiyat ekibi, stilleri bileşenlere aktarmak için Edebiyat stili kapsamının kapsamlı bir şekilde ele geçirilebildiği CSS Özel Mülklerinin kullanılmasını önerir.
Stil Etiketleri
<style>
etiketlerini şablonlarınızda satır içi olarak kullanmak da mümkündür. Tarayıcı, bu stil etiketlerini tekilleştirir, ancak bunları şablonlarınıza yerleştirildiğinde, css
etiketli şablonda olduğu gibi sınıf başına değil, bileşen örneği başına ayrıştırılır. Ayrıca, CSSResult
öğelerinin tarayıcı tekilleştirilmesi çok daha hızlıdır.
Bağlantı Etiketleri
Stiller için şablonunuzda <link rel="stylesheet">
kullanmak da mümkündür. Ancak, stillenmemiş içeriğin (FOUC) başlangıçta yanıp sönmesine neden olabileceği için bu da önerilmez.
12. İleri Düzey Konular (isteğe bağlı)
JSX ve Şablon oluşturma
Edebi ve Sanal DOM
Lit-html, her bir düğümü farklı kılan geleneksel bir Sanal DOM içermez. Bunun yerine, ES2015'in etiketli şablon değişmez değeri spesifikasyonuna uygun performans özelliklerini kullanır. Etiketli şablon değişmez değerleri, etiket işlevleri ekli olan düz şablon dizeleridir.
Değişmez şablon örneği aşağıda verilmiştir:
const str = 'string';
console.log(`This is a template literal ${str}`);
Etiketli bir düz şablon örneğini aşağıda görebilirsiniz:
const tag = (strings, ...values) => ({strings, values});
const f = (x) => tag`hello ${x} how are you`;
console.log(f('world')); // {strings: ["hello ", " how are you"], values: ["world"]}
console.log(f('world').strings === f(1 + 2).strings); // true
Yukarıdaki örnekte etiket tag
işlevidir ve f
işlevi, etiketli bir değişmez şablon çağrısını döndürür.
Edebiyat'taki performans sihrinin büyük bir kısmı, etiket işlevine iletilen dize dizilerinin aynı işaretçiye sahip olmasından kaynaklanır (ikinci console.log
içinde gösterildiği gibi). Tarayıcı, aynı değişmez şablon değerini (ör. AST'de aynı konumda) kullandığından, her etiket işlevi çağrısında yeni bir strings
dizisi yeniden oluşturmaz. Böylece Lit'in bağlama, ayrıştırma ve şablon önbelleğine alma işlemleri, çok fazla çalışma zamanı farkı ek yükü olmadan bu özelliklerden yararlanabilir.
Etiketlenmiş şablon değişmez değerlerinin bu yerleşik tarayıcı davranışı, Lit'e önemli bir performans avantajı sağlar. Geleneksel Sanal DOM'lerin çoğu, çalışmalarının büyük kısmını JavaScript'te gerçekleştirir. Bununla birlikte, etiketlenmiş şablon değişmez değerleri, farklılıklarının çoğunu tarayıcının C++'ta gerçekleştirir.
React veya Preact ile HTML etiketli şablon değişmez değerlerini kullanmak istiyorsanız Edebiyat ekibi htm
kitaplığını önerir.
Google Codelabs sitesinde ve bazı online kod düzenleyicilerinde olduğu gibi, etiketli şablonda düz yazım söz dizimi vurgulama özelliğinin çok yaygın olmadığını fark edeceksiniz. Atom ve GitHub'ın kod bloğu vurgulayıcısı gibi bazı IDE'ler ve metin düzenleyiciler varsayılan olarak bunları destekler. Edebiyat ekibi ayrıca, Edebiyat projelerinize söz dizimi vurgulama, yazım kontrolü ve bilgi toplama özellikleri ekleyen bir VS Code eklentisi olan lit-plugin
gibi projeleri sürdürmek için toplulukla çok yakın bir şekilde çalışır.
Edebi ve JSX + Tepki DOM'u
JSX tarayıcıda çalışmaz ve bunun yerine JSX'i JavaScript işlev çağrılarına (genellikle Babel üzerinden) dönüştürmek için bir ön işlemci kullanır.
Örneğin, Babel bunu dönüştürür:
const element = <div className="title">Hello World!</div>;
ReactDOM.render(element, mountNode);
şunu yaz:
const element = React.createElement('div', {className: 'title'}, 'Hello World!');
ReactDOM.render(element, mountNode);
Ardından React DOM, React çıkışını alıp gerçek DOM'ye dönüştürür (özellikler, özellikler, etkinlik işleyiciler vb.).
Lit-html, tarayıcıda aktarma veya ön işlemci olmadan çalışabilen etiketli şablon değişmez değerlerini kullanır. Diğer bir deyişle, Lit'i kullanmaya başlamak için yalnızca bir HTML dosyası, bir ES modülü komut dosyası ve bir sunucu yeterlidir. Tamamen tarayıcı tarafından çalıştırılabilen bir komut dosyası aşağıda verilmiştir:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import {html, render} from 'https://cdn.skypack.dev/lit';
render(
html`<div>Hello World!</div>`,
document.querySelector('.root')
)
</script>
</head>
<body>
<div class="root"></div>
</body>
</html>
Ayrıca, Lit'in şablon oluşturma sistemi olan lit-html, geleneksel bir Sanal DOM'u değil, doğrudan DOM API'yi kullandığından Lit 2'nin boyutu React (2, 8 kb) + 40 kb'lık küçültülmüş ve gizip uygulanmış e-tabloya kıyasla 5 kb'ın altında küçültülmüş ve gzip uygulanmıştır.
Etkinlikler
React, sentetik etkinlik sistemi kullanır. Bu, tepki-dom'un her bileşende kullanılacak her etkinliği tanımlaması ve her düğüm türü için bir camelCase etkinlik işleyici eşdeğeri sağlaması gerektiği anlamına gelir. Sonuç olarak, JSX'in özel etkinlik için etkinlik işleyici tanımlayan bir yöntemi yoktur ve geliştiricilerin ref
kullanmaları ve zorunlu olarak bir işleyici uygulaması gerekir. Bu durum, React'i dikkate almayan kitaplıkları entegre ederken vahşetin altında bir geliştirici deneyimi oluşturur ve bu nedenle React'e özel sarmalayıcı yazmak zorunda kalır.
Lit-html, DOM'ye doğrudan erişir ve yerel etkinlikleri kullanır. Dolayısıyla etkinlik işleyicileri eklemek @event-name=${eventNameListener}
kadar kolaydır. Bu, etkinlik işleyici ekleme ve etkinlik tetikleme işlemleri için daha az çalışma zamanı ayrıştırma işleminin yapıldığı anlamına gelir.
Bileşenler ve Dekorlar
Tepki bileşenleri ve özel öğeler
Gelişmiş seçeneklerde LitElement, bileşenlerini paketlemek için özel öğeler kullanır. Özel öğeler, bileşenlere ayırma söz konusu olduğunda React bileşenleri arasında bazı ödünler verir (durum ve yaşam döngüsü, Durum ve Yaşam Döngüsü bölümünde daha ayrıntılı bir şekilde açıklanmıştır).
Özel Öğelerin bileşen sistemi olarak sunduğu bazı avantajlar şunlardır:
- Tarayıcı için yereldir ve herhangi bir araç gerektirmez
innerHTML
iledocument.createElement
ilequerySelector
arasındaki her tarayıcı API'sine uyar- Genellikle çerçeveler arasında kullanılabilir
customElements.define
ve "hydrate" ile gecikmeli olarak kaydedilebilir DOM
Özel Öğelerin React bileşenlerine kıyasla bazı dezavantajları vardır:
- Sınıf tanımlamadan özel öğe oluşturulamaz (dolayısıyla JSX benzeri işlevsel bileşenler oluşturulamaz)
- Bir kapanış etiketi içermelidir
- Not: Geliştiriciye kolaylık sağlayan tarayıcı satıcıları, kendi kendine kapanan etiket spesifikasyonuna pişman olma eğilimindedir. Bu nedenle, yeni özelliklerde kendiliğinden kapanan etiketler kullanılmama eğilimindedir.
- DOM ağacına, düzen sorunlarına neden olabilecek fazladan bir düğüm ekler
- JavaScript aracılığıyla kayıtlı olmalıdır
Özel öğeler tarayıcıda yerleşik olarak bulunduğu için Lit, özelleştirilmiş öğe sistemi yerine özel öğelerle kullanmaya başladı. Lit ekibi, çerçeveler arası avantajların bileşen soyutlama katmanının sağladığı avantajlardan ağır bastığını düşünüyor. Aslına bakılırsa, Lit ekibinin lit-ssr alanındaki çalışmaları, JavaScript kaydıyla ilgili temel sorunların üstesinden gelmeyi başardı. Buna ek olarak, GitHub gibi bazı şirketler, isteğe bağlı dokunuşlarla sayfaları kademeli olarak iyileştirmek için özel öğe geç kaydından yararlanır.
Özel öğelere veri iletme
Özel öğelerle ilgili yaygın bir yanlış kanı, verilerin yalnızca dize olarak aktarılabileceğidir. Bu yanılgı, muhtemelen öğe özelliklerinin yalnızca dize olarak yazılabileceği gerçeğinden kaynaklanmaktadır. Lit, dize özelliklerini tanımlı türlerine atayacağı doğru olsa da, özel öğeler karmaşık verileri özellik olarak kabul edebilir.
Örneğin, aşağıdaki LitElement tanımını ele alalım:
// data-test.ts
import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';
@customElement('data-test')
class DataTest extends LitElement {
@property({type: Number})
num = 0;
@property({attribute: false})
data = {a: 0, b: null, c: [html`<div>hello</div>`, html`<div>world</div>`]}
render() {
return html`
<div>num + 1 = ${this.num + 1}</div>
<div>data.a = ${this.data.a}</div>
<div>data.b = ${this.data.b}</div>
<div>data.c = ${this.data.c}</div>`;
}
}
Bir özelliğin dize değerini number
değerine dönüştürecek bir temel reaktif özellik num
tanımlanır ve ardından attribute:false
ile karmaşık veri yapısı oluşturulur. Bu da Lit'in özellik işlemeyi devre dışı bırakır.
Bu özel öğeye nasıl veri iletileceği aşağıda açıklanmıştır:
<head>
<script type="module">
import './data-test.js'; // loads element definition
import {html} from './data-test.js';
const el = document.querySelector('data-test');
el.data = {
a: 5,
b: null,
c: [html`<div>foo</div>`,html`<div>bar</div>`]
};
</script>
</head>
<body>
<data-test num="5"></data-test>
</body>
Eyalet & Yaşam döngüsü
Diğer Tepki Yaşam Döngüsü Geri Çağırmaları
static getDerivedStateFromProps
Edebiyatta donanım ve durum aynı sınıf özellikleri olduğundan edebiyatta eşdeğeri yoktur
shouldComponentUpdate
- Edebiyat eşdeğeri:
shouldUpdate
- React'in aksine ilk oluşturmada çağrılır
- İşlev olarak React'in
shouldComponentUpdate
işlevine benzer
getSnapshotBeforeUpdate
Litrede getSnapshotBeforeUpdate
, hem update
hem de willUpdate
ile benzerdir
willUpdate
update
tarihinden önce arandıgetSnapshotBeforeUpdate
işlevinin aksinewillUpdate
,render
öncesinde çağrılıwillUpdate
içindeki reaktif mülklerde yapılan değişiklikler, güncelleme döngüsünü yeniden tetiklemez- Diğer özelliklere bağlı olan ve güncelleme işleminin geri kalanında kullanılan özellik değerlerini hesaplamak için iyi bir yerdir.
- Bu yöntem SSR'de sunucuda çağrıldığından burada DOM'ye erişmeniz önerilmez
update
willUpdate
tarihinden sonra arandıgetSnapshotBeforeUpdate
işlevinin aksineupdate
,render
öncesinde çağrılıupdate
ürünündeki reaktif özelliklerde yapılan değişiklikler,super.update
çağrılmadan önce değiştirilirse güncelleme döngüsünü yeniden tetiklemez- Oluşturulan çıkış DOM'ye kaydedilmeden önce bileşenin çevresindeki DOM'den bilgi yakalamak için uygun bir yerdir
- Bu yöntem SSR'de sunucuda çağrılmaz
Diğer Lit Yaşam Döngüsü Geri Çağırmaları
React'te benzer bir yaşam döngüsü geri çağırması olmadığından önceki bölümde bahsedilmeyen çeşitli yaşam döngüsü geri çağırmaları vardır. Bunlar:
attributeChangedCallback
Öğenin observedAttributes
değerlerinden biri değiştiğinde çağrılır. Hem observedAttributes
hem de attributeChangedCallback
, özel öğeler spesifikasyonunun bir parçasıdır ve Lit öğeleri için özellik API'si sağlamak üzere arka planda Lit tarafından uygulanır.
adoptedCallback
Bileşen yeni bir dokümana taşındığında (ör. HTMLTemplateElement
cihazının documentFragment
cihazından ana document
cihazına. Bu geri çağırma, özel öğeler spesifikasyonunun da bir parçasıdır ve yalnızca bileşenin dokümanları değiştirdiği gelişmiş kullanım alanları için kullanılmalıdır.
Diğer yaşam döngüsü yöntemleri ve özellikleri
Bu yöntemler ve özellikler, yaşam döngüsü sürecini değiştirmek için çağırabileceğiniz, geçersiz kılabileceğiniz veya bekleyebileceğiniz sınıf üyeleridir.
updateComplete
Bu, güncelleme ve oluşturma yaşam döngüleri eşzamansız olduğundan öğenin güncellenmesi tamamlandığında çözümlenen bir Promise
değeridir. Örnek:
async nextButtonClicked() {
this.step++;
// Wait for the next "step" state to render
await this.updateComplete;
this.dispatchEvent(new Event('step-rendered'));
}
getUpdateComplete
Bu yöntem, updateComplete
çözümlendiğinde özelleştirilmesi için geçersiz kılınması gereken bir yöntemdir. Bu durum, bir bileşen bir alt bileşen oluşturduğunda ve bunların oluşturma döngülerinin senkronize olması gerektiğinde yaygın olarak görülür. ör.
class MyElement extends LitElement {
...
async getUpdateComplete() {
await super.getUpdateComplete();
await this.myChild.updateComplete;
}
}
performUpdate
Bu yöntem, güncelleme yaşam döngüsü geri çağırma yöntemidir. Güncellemenin eşzamanlı olarak yapılması gereken nadir durumlar veya özel planlamalar dışında genellikle buna gerek yoktur.
hasUpdated
Bileşen en az bir kez güncellendiyse bu özellik true
olur.
isConnected
Özel öğeler spesifikasyonunun bir parçası. Öğe şu anda ana belge ağacına eklenmişse bu özellik true
olacaktır.
Edebiyat Güncellemesi Yaşam Döngüsü Görselleştirmesi
Güncelleme yaşam döngüsü 3 bölümden oluşur:
- Güncelleme öncesi
- Güncelle
- Güncelleme sonrası
Ön Güncelleme
requestUpdate
sonrasında planlanmış bir güncelleme bekleniyor.
Güncelle
Güncelleme Sonrası
Kancalar
Neden kancalar?
Gerekli durumun basit işlev bileşeni kullanım alanları için React'e kancalar eklendi. Birçok basit durumda, kancalı işlev bileşenleri, sınıf bileşeni eşdeğerlerinden çok daha basit ve okunabilir olma eğilimi gösterir. Yine de eşzamansız durum güncellemeleri sunmanın yanı sıra verileri kancalar veya efektler arasında aktarma konusunda, kanca modeli yeterli değildir ve reaktif denetleyiciler gibi sınıf tabanlı bir çözüm ortaya çıkma eğilimindedir.
API isteği kancaları ve kumandalar
API'den veri isteyen bir kanca yazmak yaygın bir uygulamadır. Örneğin, aşağıdakileri yapan bu React işlevi bileşenini alın:
index.tsx
- Metin oluşturur
useAPI
adlı kullanıcının yanıtını oluşturur- Kullanıcı Kimliği + Kullanıcı adı
- Hata Mesajı
- Kullanıcı 11'e ulaştığında 404 (tasarımdan)
- API getirme işlemi iptal edilirse iptal hatası
- Yükleniyor Mesajı
- Bir işlem düğmesi oluşturur
- Sonraki kullanıcı: Sonraki kullanıcı için API'yi getirir
- İptal: Bu işlem API getirme işlemini iptal eder ve bir hata gösterir.
useApi.tsx
useApi
özel kancası tanımlar- Eş zamansız olarak bir API'den kullanıcı nesnesi getirir mi?
- Emisyon:
- Kullanıcı adı
- Getirme işleminin yüklenip yüklenmediği
- Tüm hata mesajları
- Getirme işlemini iptal etmek için geri çağırma
- Kaldırılmışsa devam eden getirme işlemlerini iptal eder
Edebiyat + Reaktif Denetleyici uygulaması burada açıklanmaktadır.
Çıkarımlar:
- Reaktif Denetleyiciler, özel kancalara benzer.
- Geri çağırma işlevleri ve efektler arasında oluşturulamayan verileri iletme
- React,
useEffect
ileuseCallback
arasında veri aktarmak içinuseRef
kullanır - Edebiyat, özel sınıf mülkü kullanıyor
- Tepki, temelde özel sınıf bir mülkün davranışını taklit eder
- React,
Ayrıca, kancalı React işlevi bileşeni söz dizimini ancak Lit'in derlemesiz ortamını gerçekten seviyorsanız Lit ekibi Haunted kitaplığını kesinlikle önerir.
Çocuklar
Varsayılan Aralık
HTML öğelerine bir slot
özelliği verilmediğinde, varsayılan adsız alana atanırlar. Aşağıdaki örnekte MyApp
, adlandırılmış bir alana bir paragrafı yerleştirecektir. Diğer paragraf varsayılan olarak adsız alana ayarlanır".
@customElement("my-element")
export class MyElement extends LitElement {
render() {
return html`
<section>
<div>
<slot></slot>
</div>
<div>
<slot name="custom-slot"></slot>
</div>
</section>
`;
}
}
@customElement("my-app")
export class MyApp extends LitElement {
render() {
return html`
<my-element>
<p slot="custom-slot">
This paragraph will be placed in the custom-slot!
</p>
<p>
This paragraph will be placed in the unnamed default slot!
</p>
</my-element>
`;
}
}
Zaman Aralığı Güncellemeleri
Alan alt öğelerinin yapısı değiştiğinde bir slotchange
etkinliği tetiklenir. Lit bileşeni, etkinlik işleyiciyi bir slotchange
etkinliğine bağlayabilir. Aşağıdaki örnekte, shadowRoot
içindeki ilk alanın assignedNodes slotchange
tarihinde konsola kaydedilir.
@customElement("my-element")
export class MyElement extends LitElement {
onSlotChange(e: Event) {
const slot = this.shadowRoot.querySelector('slot');
console.log(slot.assignedNodes({flatten: true}));
}
render() {
return html`
<section>
<div>
<slot @slotchange="{this.onSlotChange}"></slot>
</div>
</section>
`;
}
}
Referanslar
Referans oluşturma
Hem Lit hem de React, render
işlevleri çağrıldıktan sonra HTMLElement'a başvuru sunar. Ancak daha sonra Lit @query
tasarımcısı veya React Referansı aracılığıyla döndürülen DOM'yi React ve Lit'in nasıl oluşturduğunu incelemek faydalı olabilir.
React, HTMLElements değil React Bileşenleri oluşturan işlevsel bir ardışık düzendir. Ref, HTMLElement oluşturulmadan önce tanımlandığı için bellekte bir alan ayrılır. Bu nedenle, gerçek DOM öğesi henüz oluşturulmadığından (veya oluşturulmadığından) (yani useRef(null)
) Ref'in ilk değeri olarak null
gösterilir.
ReactDOM, bir React Bileşenini HTMLElement'a dönüştürdükten sonra ReactComponent'ta ref
adlı bir özellik arar. ReactDOM, mevcutsa HTMLElement'ın referansını ref.current
öğesine yerleştirir.
LitElement, arka planda bir Şablon Öğesi oluşturmak için lit-html'deki html
şablon etiketi işlevini kullanır. LitElement, şablonun içeriğini, oluşturulduktan sonra özel öğenin gölge DOM'sine damgalar. Gölge DOM, bir gölge kökü ile kapsüllenmiş kapsamlı bir DOM ağacıdır. Daha sonra @query
tasarımcısı, mülk için kapsamlı kökte temel olarak bir this.shadowRoot.querySelector
gerçekleştiren bir alıcı oluşturur.
Birden Çok Öğe Sorgula
Aşağıdaki örnekte @queryAll
tasarımcısı, gölge kökündeki iki paragrafı bir NodeList
olarak döndürür.
@customElement("my-element")
export class MyElement extends LitElement {
@queryAll('p')
paragraphs!: NodeList;
render() {
return html`
<p>Hello, world!</p>
<p>How are you?</p>
`;
}
}
Temel olarak @queryAll
, paragraphs
için this.shadowRoot.querySelectorAll()
sonuçlarını döndüren bir alıcı oluşturur. JavaScript'te, bir alıcı aynı amacı yerine getirmesi gerektiği belirtilebilir:
get paragraphs() {
return this.renderRoot.querySelectorAll('p');
}
Sorgu Değiştiren Öğeler
@queryAsync
tasarımcısı, başka bir öğe özelliğinin durumuna göre değişebilen düğümleri işlemek için daha uygundur.
Aşağıdaki örnekte @queryAsync
ilk paragraf öğesini bulur. Ancak, paragraf öğesi yalnızca renderParagraph
rastgele bir tek sayı oluşturduğunda oluşturulur. @queryAsync
yönergesi, ilk paragraf kullanıma sunulduğunda çözümlenecek bir taahhüt döndürür.
@customElement("my-dissappearing-paragraph")
export class MyDisapppearingParagraph extends LitElement {
@queryAsync('p')
paragraph!: Promise<HTMLElement>;
renderParagraph() {
const randomNumber = Math.floor(Math.random() * 10)
if (randomNumber % 2 === 0) {
return "";
}
return html`<p>This checkbox is checked!`
}
render() {
return html`
${this.renderParagraph()}
`;
}
}
Arabuluculuk Durumu
React'te kural, durum React'in kendisi tarafından aracılığı olduğundan, geri çağırma yöntemidir. Tepki olarak, öğelerin sağladığı duruma güvenmemek en iyisidir. DOM, oluşturma işleminin bir etkisidir.
Harici Durum
Lit ile birlikte Redux, MobX veya başka bir eyalet yönetimi kitaplığını kullanabilirsiniz.
Lit bileşenleri, tarayıcı kapsamında oluşturulur. Dolayısıyla, tarayıcı kapsamında da bulunan tüm kitaplıklar Lit'te kullanılabilir. Lit'teki mevcut durum yönetim sistemlerinden yararlanmak için çok sayıda muhteşem kitaplık oluşturuldu.
Vaadin'in Edebiyat bileşeninde Redux'tan nasıl yararlanılacağını açıklayan bir seri.
Büyük ölçekli bir sitenin MobX in Lit'ten nasıl yararlanabileceğini görmek için Adobe'nin lit-mobx paketine göz atın.
Ayrıca, geliştiricilerin GraphQL'yi web bileşenlerine nasıl dahil ettiklerini görmek için Apollo Elements'a da göz atın.
Lit, yerel tarayıcı özellikleriyle çalışır ve tarayıcı kapsamındaki durum yönetimi çözümlerinin çoğu Lit bileşeninde kullanılabilir.
Stil
Gölge DOM
Lit, bir Özel Öğe içinde stilleri ve DOM'yi yerel olarak kapsüllemek için Gölge DOM'u kullanır. Gölge Kökleri, ana belge ağacından ayrı bir gölge ağacı oluşturur. Bu, çoğu stilin bu doküman kapsamında yer aldığı anlamına gelir. Renk ve yazı tipiyle ilgili diğer stiller gibi belirli stiller sızdırılır.
Gölge DOM, CSS spesifikasyonuna yeni kavramlar ve seçiciler de ekliyor:
:host, :host(:hover), :host([hover]) {
/* Styles the element in which the shadow root is attached to */
}
slot[name="title"]::slotted(*), slot::slotted(:hover), slot::slotted([hover]) {
/*
* Styles the elements projected into a slot element. NOTE: the spec only allows
* styling the direcly slotted elements. Children of those elements are not stylable.
*/
}
Stilleri paylaşma
Lit, css
şablon etiketleri aracılığıyla bileşenler arasında CSSTemplateResults
biçimindeki stillerin paylaşılmasını kolaylaştırır. Örneğin:
// typography.ts
export const body1 = css`
.body1 {
...
}
`;
// my-el.ts
import {body1} from './typography.ts';
@customElement('my-el')
class MyEl Extends {
static get styles = [
body1,
css`/* local styles come after so they will override bod1 */`
]
render() {
return html`<div class="body1">...</div>`
}
}
Tema oluşturma
Gölge kökleri, genellikle yukarıdan aşağıya stil etiket yaklaşımları olan geleneksel tema oluşturma için biraz zorluk teşkil eder. Gölge DOM kullanan Web Bileşenleriyle tema oluşturma işlemi yapmak için geleneksel yöntem, CSS Özel Özellikleri aracılığıyla bir stil API'si sunmaktır. Örneğin, şu Materyal Tasarım'ın kullandığı bir kalıptır:
.mdc-textfield-outline {
border-color: var(--mdc-theme-primary, /* default value */ #...);
}
.mdc-textfield--input {
caret-color: var(--mdc-theme-primary, #...);
}
Bu işlemin ardından kullanıcı, özel özellik değerleri uygulayarak sitenin temasını değiştirir:
html {
--mdc-theme-primary: #F00;
}
html[dark] {
--mdc-theme-primary: #F88;
}
Yukarıdan aşağıya tema oluşturmak zorundaysanız ve stilleri gösteremiyorsanız her zaman createRenderRoot
değerini geçersiz kılarak Gölge DOM'u devre dışı bırakarak this
sonucunu döndürebilirsiniz. Bu durumda bileşenleriniz oluşturulur. şablonunu, özel öğeye ekli bir gölge kökü yerine özel öğenin kendisine ekler. Bu durumda şunları kaybedersiniz: stil kapsülleme, DOM kapsülleme ve alanlar.
Üretim
İrlanda 11
IE 11 gibi daha eski tarayıcıları desteklemeniz gerekiyorsa, yaklaşık 33 KB'lık bir boyuta gelen bazı çoklu dolguları yüklemeniz gerekecektir. Daha fazla bilgiye buradan ulaşabilirsiniz.
Koşullu Paketler
Lit ekibi, biri IE 11, diğeri modern tarayıcılar için olmak üzere iki farklı paket sunmanızı öneriyor. Bunun bazı avantajları vardır:
- ES 6, daha hızlı sunulur ve müşterilerinizin çoğuna hizmet verir
- Aktarılan ES 5, paket boyutunu önemli ölçüde artırıyor
- Koşullu paketler iki olanaktan en iyi şekilde yararlanmanızı sağlar.
- IE 11 desteği
- Modern tarayıcılarda yavaşlama yok
Koşullu olarak sunulan paket oluşturma hakkında daha fazla bilgiyi buradaki belge sitemizde bulabilirsiniz.