1. Giriş
Edebiyat nedir?
Lit, herhangi bir çerçevede veya hiç çerçeve olmadan çalışan hızlı, hafif web bileşenleri oluşturmak için kullanılan basit bir kitaplıktır. Lit'i kullanarak paylaşılabilir bileşenler, uygulamalar, tasarım sistemleri ve daha fazlasını oluşturabilirsiniz.
Neler öğreneceksiniz?
Aşağıdakiler gibi çeşitli React kavramlarını Lit'e çevirme:
- JSX ve Şablon Oluşturma
- Bileşenler ve Özellikler
- Durum ve Yaşam Döngüsü
- Kancalar
- Çocuklar
- Referanslar
- Arabulucu Eyalet
Ne oluşturacaksınız?
Bu codelab'in sonunda React bileşeni kavramlarını Lit analoglarına dönüştürebileceksiniz.
İhtiyacınız olanlar
- Chrome, Safari, Firefox veya Edge'in en son sürümü.
- HTML, CSS, JavaScript ve Chrome Geliştirici Araçları hakkında bilgi sahibi olmanız gerekir.
- React hakkında bilgi sahibi olma
- (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 özellikleri birçok açıdan React'e benzer ancak Lit'in bazı temel farklılıkları ve ayırt edici özellikleri de vardır:
Küçük
Lit çok küçüktür: React + ReactDOM'un 40'tan fazla kb boyutuna kıyasla, sıkıştırılmış ve gzip'lenmiş haliyle yaklaşık 5 kb'tır.
Hızlı
Lit'in şablonlama sistemi olan lit-html'yi React'in VDOM ile karşılaştıran herkese açık karşılaştırmalarda, en kötü durumda lit-html React'ten %8-10 daha hızlı, daha yaygın kullanım alanlarında ise %50'den daha hızlı görünüyor.
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.
ES modülleri ve Skypack veya UNPKG gibi modern CDN'ler sayesinde, başlamak için NPM'ye bile ihtiyacınız olmayabilir.
Ancak isterseniz Lit kodu 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, Lit ile oluşturulan bileşenlerin mevcut ve gelecekteki çerçevelerde çalışacağı anlamına gelir. HTML öğelerini destekliyorsa Web Bileşenleri'ni de destekler.
Çerçeveler arasındaki birlikte çalışabilirlikle ilgili tek sorun, çerçevelerin DOM için kısıtlayıcı destek sunması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ıya yerleştirilmiştir
Basit bileşenler yalnızca DOM'de bulunan HTML öğeleridir. Diğer bir deyişle, bileşenlerinizi incelemek için tarayıcınız için herhangi bir araç veya uzantı yüklemeniz gerekmez.
Yalnızca geliştirici 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 kod laboratuvarının yazıldığı sırada Lit ekibi, SSR araçlarını kararlı bir biçimde henüz yayınlamamıştı ancak Lit ekibi, sunucu tarafı oluşturulan bileşenleri Google ürünlerinde kullanıma sunmuş ve SSR'yi React uygulamalarında test etmişti. Lit ekibi bu araçları yakında GitHub'da harici olarak kullanıma sunmayı umuyor.
Bu süreçte Lit ekibinin kaydettiği ilerlemeyi buradan takip edebilirsiniz.
Katılımı azdır.
Lit'i kullanmak için önemli bir taahhütte bulunmanız gerekmez. Lit'te bileşenler oluşturabilir ve bunları 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 uygulamanın tamamını oluşturdunuz ve başka bir platforma geçmek mi istiyorsunuz? O zaman mevcut Lit uygulamanızı yeni çerçevenizin içine yerleştirip istediğiniz her şeyi yeni çerçevenin bileşenlerine taşıyabilirsiniz.
Ayrıca, birçok modern çerçeve, web bileşenlerinde çıkışı destekler. Bu da genellikle bir Lit öğesinin içine sığabilecekleri anlamına gelir.
3. Playground'u hazırlama ve keşfetme
Bu codelab'i iki şekilde yapabilirsiniz:
- Bu işlemi tamamen online olarak tarayıcıda yapabilirsiniz.
- (Gelişmiş) Bu işlemi VS Code'u kullanarak yerel makinenizde yapabilirsiniz
Koda erişme
Codelab'de Lit oyun alanına giden bağlantılar bulunur. Örneğin:
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 çözebilir (ö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ıç noktası olarak kullanarak eğitimimizin tamamını Lit eğitim alanında yapabilirsiniz. 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 kullanabilirsiniz.
Lit oyun alanı kullanıcı arayüzünü keşfetme
Lit playground kullanıcı arayüzü ekran görüntüsünde, bu kod laboratuvarında kullanacağınız bölümler vurgulanmıştır.
- Dosya seçici. Artı düğmesine dikkat edin...
- Dosya düzenleyici.
- Kod önizlemesi.
- Yeniden yükle düğmesi.
- İndir düğmesi.
VS Code kurulumu (Gelişmiş)
Bu VS Kodu kurulumunu kullanmanın avantajları şunlardır:
- Şablon türü kontrolü
- Şablon akıllı yardım ve otomatik tamamlama
NPM ve 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şlatabilirsiniz:
- İ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, Lit'te şablon oluşturmanın temellerini öğreneceksiniz.
JSX ve Edebiyat ş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şturacaksınız:
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" değişkeni bulunmaktadır. 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ındaki birden fazla öğeyi gruplandırmak için React Fragment'e ihtiyaç duymadığını unutmayın.
Lit'te şablonlar html
etiketli şablon LITeral ile sarmalanır. Lit'in adı da buradan gelir.
Ş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 olarak 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 dizimi arasındaki en büyük farklardan biri veri bağlama söz dizimidir. Örneğin, aşağıdaki React girişini bağlayıcılarla birlikte ele alalım:
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ımlanmıştı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
);
Lit örneğinde, disabled
özelliğini açma/kapatma için bir boole bağlaması eklenmiştir.
Ardından, className
yerine doğrudan class
özelliğine bağlanma işlemi vardır. Sınıfları değiştirmek için açıklayıcı bir yardımcı olan classMap
yönergesini kullanmıyorsanız class
özelliğine birden fazla bağlama eklenebilir.
Son olarak, girişte value
özelliği ayarlanır. React'ten farklı olarak bu işlem, input öğesinin yerel uygulamasını ve davranışını takip ettiği için 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ğerdisabled="false"
, DOM tarafından doğru olarak okunmaya devam ettiğindeninputElement.hasAttribute('disabled') === true
içindisabled
kullanan öğeler için kullanışlıdır.
html`<my-element .property-name=${anyVar}>`;
.
ön eki, bir öğenin özelliğini ayarlamak için kullanılan bağlama söz dizimidir.inputRef.propertyName = anyVar
değerine 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)
değerine 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ımlanmıştır:
- Giriş tıklandığında "tıkla" kelimesini günlüğe kaydetme
- Kullanıcı bir karakter yazdığında girişin değerini günlüğe kaydetme
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', ...)
değerine eşdeğer- Yerel DOM etkinlik adlarını kullanır
5. Bileşenler ve Özellikler
Bu bölümde, Lit sınıf bileşenleri ve işlevleri hakkında bilgi edineceksiniz. Durum ve Hooks, sonraki bölümlerde daha ayrıntılı olarak ele alınmaktadır.
Sınıf Bileşenleri ve LitElement
Bir React sınıfı bileşeninin Edebiyat eşdeğeri LitElement'tır ve Lit'in "reaktif özellikler" kavramı, React'in eşyalar ve durumunun bir 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:
- Bir
name
oluşturur name
politikasının varsayılan değerini boş dize (""
) olarak ayarlar.name
adlı kişiyi"Elliott"
adlı kullanıcıya yeniden atar
LitElement'te bunu ş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ğuyla ilgili 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 süsleyicisinin 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
Lit, JSX veya önişleyici kullanmadığından işlev bileşeninin 1:1 yorumuna sahip değildir. Ancak, özellikleri alan ve DOM'u bu özelliklere göre oluşturmaya yönelik 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. Durum ve 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 özelliklerinin bir karışımıdır. Reaktif özellikler değiştirildiğinde bileşen yaşam döngüsünü tetikleyebilir. Reaktif mülkler iki varyantta gelir:
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';
}
@property
tarafından tanımlanmıştır- React'in props ve state'ine benzer ancak 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';
}
@state
tarafından tanımlanmıştır- 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';
}
}
- Lit eşdeğeri de
constructor
'tür. - Süper çağrıya herhangi bir bilgi iletmeye gerek yoktur.
- Çağıran (tamamen dahil değildir):
document.createElement
document.innerHTML
new ComponentClass()
- Sayfada yükseltme yapılmamış bir etiket adı varsa ve tanım yüklenip
@customElement
veyacustomElements.define
ile kaydedilmişse
- 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 sonuç döndürebilir (ör.
TemplateResult
veyastring
vb.). - React'e benzer şekilde,
render()
saf 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ğırma yöntemlerinin bir 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. söz konusu 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, özel öğeler DOM'den kaldırıldığında yok edilmez ve bu nedenle birden çok kez "bağlanabilir"
firstUpdated
tekrar aranmayacak
- DOM'u yeniden başlatmak veya bağlantı kesildiğinde temizlenen etkinlik işleyicileri yeniden eklemek için kullanışlıdır.
- Not:
connectedCallback
,firstUpdated
'den önce çağrılabilir. Bu nedenle, ilk çağrıda 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);
}
}
- Yazılı eşdeğeri
updated
("update" kelimesinin İngilizce geçmiş zaman kipi kullanılır) - React'in aksine
updated
, ilk oluşturma sırasında da çağrılır - 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);
}
- Lit eşdeğeri
disconnectedCallback
ile benzer - React bileşenlerinin aksine, DOM'den özel öğeler çıkarıldığında bileşen kaldırılmaz
componentWillUnmount
'ün 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 çöpe atabilmesi 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:
- "Merhaba Dünya! Saat şu anda" ve ardından saati gösterir.
- Saniyede bir saati günceller.
- Ayrıldığında, işareti çağıran aralığı temizler
Öncelikle bileşen sınıfı beyanıyla 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
'ün uygulanması gelir. Yine de, Lit analogu firstUpdated
ve connectedCallback
'un 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. Bu nedenle, öğe yeniden bağlanırsa aralığın yeniden başlatılması gerekir. Bu nedenle, burada connectedCallback
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. Giriş cümleleri
Bu bölümde React Hook kavramlarını Edebiyat'a nasıl çevireceğinizi öğreneceksiniz.
React kancaları kavramları
React kancaları, işlev bileşenlerinin duruma "kanca" bağlamasına olanak tanır. Bunun birkaç avantajı vardır.
- Durum bilgisine sahip mantığın yeniden kullanımını basitleştirir.
- Bir bileşeni daha küçük işlevlere ayırmanıza yardımcı olur.
Ek olarak, işlev tabanlı bileşenlere odaklanma, React'in sınıfa dayalı söz dizimiyle ilgili şu gibi sorunları ele aldı:
props
'üconstructor
'dansuper
'ye aktarmanız gerekir.constructor
- içindeki özelliklerin düzenli şekilde başlatılması
- Bu, React ekibi tarafından o dönemde belirtilen bir nedendi ancak ES2019 ile çözüldü.
this
nedeniyle ortaya çıkan sorunlar artık bileşene atıfta bulunmuyor
Edebiyat'taki tepki kancası kavramları
Bileşenler ve Öğeler bölümünde belirtildiği gibi, Lit bir işlevden özel öğeler oluşturmanın bir yolunu 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- Tüm
@event
bağlamalarıthis
'a otomatik olarak bağlanır this
, çoğu durumda özel öğenin referansını ifade eder.- Sınıf özellikleri artık sınıf üyeleri olarak örneklenebilir. Bu, kurucu tabanlı uygulamaları temizler.
Reaktif Denetleyiciler
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
'un yaşam döngüsü:
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, Durum ve Yaşam Döngüsü bölümündeki saat örneğini hatırlayın:
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:
- "Merhaba Dünya! Saat" ve ardından saati gösterir.
- Saniyede bir saati günceller.
- 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. Özet:
componentDidMount
- LitElement'ın
connectedCallback
cihazına - Denetleyicinin
hostConnected
- LitElement'ın
ComponentWillUnmount
- LitElement'ın
disconnectedCallback
cihazına - Denetleyicinin
hostDisconnected
- LitElement'ın
React yaşam döngüsünü Lit yaşam döngüsüne çevirme hakkında daha fazla bilgi için Durum ve Yaşam Döngüsü bölümüne bakın.
Daha sonra, hostConnected
geri çağırması ile tick
yöntemlerini uygulayıp hostDisconnected
aralığındaki aralığı, Durum ve Yaşam Döngüsü bölümündeki örnekte gösterildiği gibi temizleyin.
// 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şeni) bir referans göndererek denetleyiciyi örneklemeniz ve ardından denetleyiciyi render
yönteminde kullanmanız gerekir.
Denetleyicide yeniden oluşturma işlemlerini tetikleme
Saatin gösterildiğini ancak güncellenmediğini fark edin. Bunun nedeni, denetleyicinin tarihi her saniye ayarlamasına rağmen ana makinenin güncellenmemesinden kaynaklanı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();
}
Artık zaman daralı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.
Slot ve Çocuk
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 yuva props.children
'tür ve render
işlevi, varsayılan yuvanın nerede konumlandırıldığını 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.
Lit'te 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 fazla slot
React'te birden fazla yuva eklemek, temelde daha fazla öğe devralmakla aynıdır.
const MyArticle = (props) => {
return (
<article>
<header>
{props.headerChildren}
</header>
<section>
{props.sectionChildren}
</section>
</article>
);
};
Benzer şekilde, daha fazla <slot>
öğesi eklemek Lit'te daha fazla slot oluşturur. name
özelliğiyle birden fazla slot tanımlanmış: <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
Bu aralığa yansıtılan düğüm olmadığında aralıklar 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, bileşenin özellikleri aracılığıyla yuvalara atanır. Aşağıdaki örnekte, React öğeleri headerChildren
ve sectionChildren
öğelerine iletilmektedir.
const MyNewsArticle = () => {
return (
<MyArticle
headerChildren={<h3>Extry, Extry! Read all about it!</h3>}
sectionChildren={<p>Children are props in React!</p>}
/>
);
};
Lit'te alt öğeler, slot
özelliği kullanılarak yuvalara 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. Referanslar
Geliştiricilerin bazen bir HTMLElement'in API'sine erişmesi gerekebilir.
Bu bölümde, Lit'te öğ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 Refs, oluşturulan bir HTMLElement'i barındırmak için bellekte yerdir.
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 odaklanma
İlk oluşturma işleminden sonra React, ref
özelliği aracılığıyla oluşturulan HTMLInputElement
öğesine inputRef.current
değerini ayarlar.
"Referanslar"ı @query
ile aydınlattı
Lit, tarayıcıya yakın bir yerde bulunur ve yerel tarayıcı özellikleri üzerinde çok ince bir soyutlama oluşturur.
Edebiyat'taki refs
işlevinin Tepki olarak eşdeğeri, @query
ve @queryAll
tasarımcıları tarafından döndürülen HTMLElement'tır.
@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
süsleyicisini kullanarakMyElement
üzerinde bir mülk tanımlar (HTMLInputElement
için bir alıcı oluşturur).onButtonClick
adlı bir tıklama etkinliği geri çağırma işlevi tanımlar ve ekler.- Düğme tıklandığında girişe odaklanır
JavaScript'te @query
ve @queryAll
süsleyicileri sırasıyla querySelector
ve querySelectorAll
işlemlerini gerçekleştirir. Bu, @query('input') inputEl!: HTMLInputElement;
değerinin 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 bulamıyorsa null
döndürülü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, Lit'teki bileşenler arasında durumu nasıl uyumlulaştıracağınızı öğreneceksiniz.
Yeniden Kullanılabilir Bileşenler
React, yukarıdan aşağıya veri akışıyla işlevsel oluşturma ardışık düzenlerini taklit eder. Ebeveynler, çocuklara sahne öğeleri aracılığıyla durum sağlar. Çocuklar, öğelerde bulunan geri çağırma işlevleri aracılığıyla 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 aşağıdakileri yapar:
props.step
değerine göre bir etiket oluşturur.- Etiketi +step veya -step olan bir düğme oluşturur
- Tıklama üzerine
props.step
bağımsız değişkeni ileprops.addToCounter
çağrılarak üst bileşeni günceller
Lit'te geri çağırma işlevleri iletilebilir ancak geleneksel kalıplar farklıdır. Yukarıdaki örnekte bulunan 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 aşağıdakileri yapar:
- Reaktif mülkü
step
oluşturun - Tıklama sırasında öğenin
step
değerini taşıyanupdate-counter
adlı özel bir etkinlik gönderme
Tarayıcı etkinlikleri, alt öğelerden üst öğelere doğru yükselir. Etkinlikler, çocukların etkileşim etkinliklerini ve durum değişikliklerini yayınlamasına olanak tanır. React temel olarak durumu ters yönde iletir. Bu nedenle, React bileşenlerinin Lit bileşenleriyle aynı şekilde etkinlik gönderip dinlediğini görmek nadirdir.
Durum Bilgili Bileşenler
React'te durumu yönetmek için kancalar yaygın olarak kullanılır. CounterButton
bileşeni yeniden kullanılarak 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
değerinistep
değerine göre güncellemek içinaddToCounter
işlevini kullanır.
Lit'te MyCounter
için benzer bir uygulama elde edilebilir. addToCounter
, counter-button
'a nasıl iletilmediğine 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ğlarupdate-counter
etkinliğinindetail.step
parametresinde bulunan değeri ekleyerekcount
parametresini günceller.step
özelliği aracılığıylacounter-button
öğesininstep
değerini 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
Lit, öğelere stil uygulamanın birden fazla yolunu ve yerleşik bir çözümü sunar.
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
directive, 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 örnekte aşağıdakiler yapılır:
- 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
Ayrıca, h1
stillerini ayarlamak için kullanılan styleMap
vardır. styleMap
, React'in style
özellik bağlama söz dizimine benzer bir söz dizimi kullanır.
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 örnekte aşağıdakiler yapılır:
- Bağlama sahip bir CSS etiketli şablon literali tanımlar
- Kimlikleri olan 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üllerin yeniden kullanılabilirliği göz önünde bulundurularak uygulanır.
- Stilleri kendi dosyalarına kolayca 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>
Lit, bileşenlerinizin stillerini köklerine göre kapsamlandırır. Bu sayede, stiller içeri ve dışarı sızmaz. Lit ekibi, stilleri bileşenlere aktarmak için Lit stil kapsamına girebilecekleri için CSS Özel Özellikleri kullanmanızı önerir.
Stil Etiketleri
Şablonlarınıza <style>
etiketlerini satır içi olarak da ekleyebilirsiniz. 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, tarayıcıda CSSResult
'lerin tekilleştirilmesi çok daha hızlıdır.
Bağlantı Etiketleri
Stiller için şablonunuzda <link rel="stylesheet">
kullanılması 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. Gelişmiş Konular (isteğe bağlı)
JSX ve Şablonlama
Lit ve Sanal DOM
Lit-html, her bir düğümü karşılaştıran geleneksel bir sanal DOM içermez. Bunun yerine, ES2015'in etiketli şablon literali spesifikasyonuna özgü performans özelliklerini kullanır. Etiketli şablon literalleri, etiket işlevlerinin eklendiği şablon literal dizelerdir.
Değişmez şablon örneği aşağıda verilmiştir:
const str = 'string';
console.log(`This is a template literal ${str}`);
Etiketli şablon literal'ine örnek:
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 şablon değişmez değerinin çağrısını döndürür.
Lit'teki performansın çoğu, etiket işlevine iletilen dize dizilerinin aynı işaretçiye sahip olmasından kaynaklanır (ikinci console.log
'te gösterildiği gibi). Tarayıcı, aynı şablon literalini (yani AST'deki aynı konumu) kullandığı için her etiket işlevi çağrısında yeni bir strings
dizisi oluşturmaz. Bu nedenle Lit'in bağlama, ayrıştırma ve şablon önbelleğe alma özellikleri, çalışma zamanında fazla fark çıkarma yükü olmadan bu özelliklerden yararlanabilir.
Etiketli şablon literallerinin 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.
Ancak Google Codelabs sitesinde ve çeşitli online kod düzenleyicilerde olduğu gibi, etiketli şablon literal söz dizimi vurgulamasının ç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 bunları varsayılan olarak destekler. Lit ekibi, Lit projelerinize söz dizimi vurgulama, tür kontrolü ve akıllı sözcük önerme ekleyen bir VS Code eklentisi olan lit-plugin
gibi projeleri sürdürmek için toplulukla çok yakın bir şekilde çalışır.
Lit ve JSX + React DOM
JSX tarayıcıda çalışmaz. Bunun yerine, JSX'i JavaScript işlev çağrılarına dönüştürmek için bir önişleyici kullanır (genellikle Babel aracılığıyla).
Örneğin, Babel bunu dönüştürür:
const element = <div className="title">Hello World!</div>;
ReactDOM.render(element, mountNode);
şu şekilde değiştirilir:
const element = React.createElement('div', {className: 'title'}, 'Hello World!');
ReactDOM.render(element, mountNode);
Ardından React DOM, React çıkışını alıp mülkler, özellikler, etkinlik işleyiciler ve diğer tüm öğelerle birlikte gerçek DOM'a çevirir.
Lit-html, kod dönüştürme veya önişleyici olmadan tarayıcıda çalışabilen etiketli şablon literalleri 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 küçültülmüş ve gizip uygulanmış e-postaya kıyasla 5 kb'ın altında küçültülmüş ve gzip uygulanmıştır.
Etkinlikler
React sentetik bir etkinlik sistemi kullanır. Bu, react-dom'un her bileşende kullanılacak her etkinliği tanımlaması ve her düğüm türü için camelCase etkinlik dinleyici eşdeğeri sağlaması gerektiği anlamına gelir. Sonuç olarak, JSX'te özel bir etkinlik için etkinlik dinleyici tanımlama yöntemi yoktur ve geliştiricilerin bir ref
kullanması ve ardından zorunlu olarak bir dinleyici uygulaması gerekir. Bu durum, React'i göz önünde bulundurmayan kitaplıkları entegre ederken geliştirici deneyimini olumsuz etkiler ve React'e özel bir sarmalayıcı yazmak zorunda kalmanıza neden olur.
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 Özellikler
React bileşenleri ve özel öğeler
LitElement, bileşenlerini paketlemek için özel öğeleri 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ıya özgüdür ve herhangi bir araç gerektirmez.
innerHTML
vedocument.createElement
ilequerySelector
arasındaki her tarayıcı API'sine uyar- Genellikle çerçeveler arasında kullanılabilir
customElements.define
ile üşengeç şekilde kaydedilebilir ve DOM'u "etkinleştirebilir"
Özel öğelerin React bileşenlerine kıyasla bazı dezavantajları:
- Sınıf tanımlamadan özel öğe oluşturulamaz (bu nedenle JSX benzeri işlevsel bileşenler kullanılamaz)
- Kapanış etiketi içermelidir
- Not: Geliştiricilere kolaylık sağlamasına rağmen tarayıcı tedarikçileri, kendi kendini kapatan etiket spesifikasyonundan pişman olma eğilimindedir. Bu nedenle, yeni spesifikasyonlarda kendi kendini kapatan etiketler bulunmaz.
- DOM ağacına, düzen sorunlarına neden olabilecek fazladan bir düğüm ekler
- JavaScript üzerinden kaydedilmelidir.
Lit, özel öğeler tarayıcıya yerleştirildiği için özel öğeler yerine özel öğe sistemi kullanmayı tercih etti. Lit ekibi, çerçeveler arası avantajların bir bileşen soyutlama katmanı tarafından sağlanan avantajlardan daha ağır bastığına inanıyor. Aslında Lit ekibinin lit-ssr alanındaki çalışmaları, JavaScript kaydıyla ilgili temel sorunların üstesinden geldi. 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ış anlama, verilerin yalnızca dize olarak iletilebileceğidir. Bu yanlış anlama, muhtemelen öğe özelliklerinin yalnızca dize olarak yazılabilmesinden 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 ilkel bir reaktif mülk num
tanımlanır ve ardından Lit'in özellik işlemesini devre dışı bırakan attribute:false
ile karmaşık veri yapısı tanıtılı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>
Durum ve Yaşam Döngüsü
Diğer Tepki Yaşam Döngüsü Geri Çağırmaları
static getDerivedStateFromProps
Lit'te, props ve state aynı sınıf özellikleri olduğundan eşdeğeri yoktur.
shouldComponentUpdate
- Lit eşdeğeri
shouldUpdate
- React'in aksine ilk oluşturma işleminde çağrılır.
- React'in
shouldComponentUpdate
işlevine benzer
getSnapshotBeforeUpdate
Lit'te getSnapshotBeforeUpdate
hem update
hem de willUpdate
ile benzer
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 benzerleri olmadığı için önceki bölümde bahsedilmeyen birkaç yaşam döngüsü geri çağırma işlevi vardır. Bunları şöyle sıralayabiliriz:
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 (ör. bir HTMLTemplateElement
'nin documentFragment
'inden ana document
'ye) taşındığında çağrılır. Bu geri çağırma, özel öğeler spesifikasyonunun bir parçasıdır ve yalnızca bileşenin doküman değiştirdiği ileri düzey 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, updateComplete
'ün çözüldüğü zamanı özelleştirmek için geçersiz kılınması gereken bir yöntemdir. Bu durum, bir bileşen bir alt bileşen oluştururken ve bunların oluşturma döngülerinin senkronize olması gerektiğinde yaygın olarak görülür. Örneğin,
class MyElement extends LitElement {
...
async getUpdateComplete() {
await super.getUpdateComplete();
await this.myChild.updateComplete;
}
}
performUpdate
Yaşam döngüsü güncelleme geri çağırma yöntemlerini bu yöntem çağırır. Güncellemenin senkronize olarak yapılması gereken nadir durumlar veya özel planlama dışında genellikle bu işleme 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üncellemeden önce
- Güncelle
- Güncelleme sonrası
Ön Güncelleme
requestUpdate
tarihinden sonra planlanmış bir güncelleme beklenir.
Güncelle
Güncelleme sonrası
Giriş cümleleri
Neden kancalar?
Gerekli durumun basit işlev bileşeni kullanım alanları için React'e kancalar eklendi. Basit durumlarda, kanca içeren işlev bileşenleri, sınıf bileşeni eşdeğerlerinden çok daha basit ve okunaklı olma eğilimindedir. 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 istek kancaları ve denetleyicileri
Bir 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ı
- İşlem düğmesi oluşturur
- Sonraki kullanıcı: Sonraki kullanıcı için API'yi getirir
- İptal: API getirme işlemini durdurur 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ükleniyor olup olmadığı
- 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
Lit + Reactive Controller uygulaması aşağıda verilmiştir.
Çıkarımlar:
- Reaktif denetleyiciler, özel kancalara en çok benzeyen denetleyicilerdir.
- 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
- React, temel olarak özel sınıf mülkünü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 Slot
HTML öğelerine bir slot
özelliği verilmediğinde, varsayılan adsız alana atanırlar. Aşağıdaki örnekte, MyApp
bir paragrafı adlandırılmış bir alana yerleştirir. 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>
`;
}
}
Slot Güncellemeleri
Yuva 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çinde bulunan ilk yuvanın assignedNodes özelliği slotchange
'da 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 bir HTMLElement referansı gösterir. Ancak daha sonra Edebiyat @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, HTMLElement 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. Gerçek DOM öğesi henüz oluşturulmadığı (veya oluşturulmadığı) için Ref öğesinin ilk değeri olarak null
gösterilir. useRef(null)
ReactDOM, bir React bileşenini HTMLElement'e dönüştürdükten sonra ReactComponent'te 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şturduktan sonra özel bir öğenin gölge DOM'una 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
işlemi gerçekleştiren bir alıcı oluşturur.
Birden Çok Öğeyi Sorgulama
Aşağıdaki örnekte, @queryAll
süsleyici, gölge kökteki iki paragrafı 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
süsleyici, başka bir öğe mülkünün durumuna göre değişebilen bir düğümü işlemek için daha uygundur.
Aşağıdaki örnekte @queryAsync
ilk paragraf öğesini bulur. Ancak paragraf öğesi yalnızca renderParagraph
rastgele tek bir sayı oluşturduğunda oluşturulur. @queryAsync
yönü, ilk paragraf mevcut olduğunda çözülecek bir söz 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 durum yönetimi kitaplığı kullanabilirsiniz.
Lit bileşenleri tarayıcı kapsamında oluşturulur. Bu nedenle, tarayıcı kapsamında da bulunan tüm kitaplıklar Lit tarafından 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 Lit'te MobX'ten nasıl yararlanabileceğini görmek için Adobe'un lit-mobx paketine göz atın.
Ayrıca, geliştiricilerin GraphQL'yi web bileşenlerine nasıl dahil ettiğini görmek için Apollo Elements'e göz atın.
Lit, yerel tarayıcı özellikleriyle çalışır ve tarayıcı kapsamındaki durum yönetimi çözümlerinin çoğu Edebiyat 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ökler, ana doküman ağacından ayrı bir gölge ağacı oluşturur. Bu, çoğu stilin kapsamının bu dokümanla sınırlı olduğu 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 CSSTemplateResults
biçiminde bileşenler arasında stil paylaşmayı 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, aşağıdaki Materyal Tasarım'da kullanılan 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ğı tema oluşturma zorunluysa ve stilleri gösteremiyorsanız createRenderRoot
değerini geçersiz kılarak this
döndürerek Shadow DOM'u devre dışı bırakabilirsiniz. Bu durumda bileşenlerinizin şablonu, özel öğeye bağlı bir gölge kök yerine özel öğenin kendisine oluşturulur. Bu durumda stil kapsüllemeyi, DOM kapsüllemeyi ve yuvaları kaybedersiniz.
Üretim
İrlanda 11
IE 11 gibi eski tarayıcıları desteklemeniz gerekiyorsa yaklaşık 33 KB daha ek polyfill yüklemeniz gerekir. Daha fazla bilgiye buradan ulaşabilirsiniz.
Koşullu Paketler
Lit ekibi, biri IE 11 ve diğeri modern tarayıcılar için olmak üzere iki farklı paket yayınlamanızı önerir. Bunun birkaç avantajı 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 gruplar, iki dünyanın da en iyisini sunar
- IE 11 desteği
- Modern tarayıcılarda yavaşlama olmaz
Koşullu olarak sunulan paket oluşturma hakkında daha fazla bilgiyi buradaki belge sitemizde bulabilirsiniz.