1. Giriş
Lit nedir?
Lit, herhangi bir çerçevede veya çerçeve olmadan çalışan hızlı ve hafif web bileşenleri oluşturmak için kullanılan basit bir kitaplıktır. Lit ile 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 Öğeler
- Durum ve Yaşam Döngüsü
- Dikkat çekici girişler
- Çocuklar
- Refs
- Aracılık durumu
Ne oluşturacaksınız?
Bu codelab'in sonunda, React bileşen kavramlarını Lit'teki benzerlerine 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 olmak
- React bilgisi
- (Gelişmiş) En iyi geliştirme deneyimini istiyorsanız VS Code'u indirin. Ayrıca VS Code için lit-plugin ve NPM'ye de ihtiyacınız olacaktır.
2. Lit ve React
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 KB'den fazla olmasına karşın Lit, küçültülmüş ve sıkıştırılmış olarak yaklaşık 5 KB'tır.

Hızlıdır.
Lit'in şablon sistemini (lit-html) React'in VDOM'uyla karşılaştıran kamu kıyaslamalarında, en kötü durumda lit-html'in React'ten % 8-10 daha hızlı, daha yaygın kullanım alanlarında ise %50'den fazla daha hızlı olduğu görülmektedir.
LitElement (Lit'in bileşen temel sınıfı), lit-html'ye minimum ek yük getirir ancak bellek kullanımı, etkileşim ve başlatma süreleri gibi bileşen özellikleri karşılaştırıldığında React'in performansını%16-30 oranında aşar.

Derleme gerektirmez
ES modülleri ve etiketlenmiş şablon değişmezleri gibi yeni tarayıcı özellikleriyle Lit'in çalışması için derleme yapılması gerekmez. Bu, geliştirme ortamlarının bir komut dosyası etiketi, bir tarayıcı ve bir sunucu ile kurulabileceği ve hemen çalışmaya başlayabileceğiniz anlamına gelir.
ES modülleri ve Skypack veya UNPKG gibi modern CDN'ler ile başlamak için NPM'ye bile ihtiyacınız olmayabilir.
Ancak isterseniz Lit kodunu oluşturup optimize etmeye devam edebilirsiniz. Yerel ES modülleri etrafındaki son geliştirici birleşimi Lit için iyi oldu. Lit, normal JavaScript'tir ve çerçeveye özgü CLI'ler veya derleme işleme gerekmez.
Çerçeveden bağımsız
Lit'in bileşenleri, Web Bileşenleri adı verilen bir dizi web standardı üzerine kuruludur. Bu, Lit'te oluşturulan bir bileşenin mevcut ve gelecekteki çerçevelerde çalışacağı anlamına gelir. HTML öğelerini destekliyorsa Web Bileşenleri'ni de destekler.
Çerçeveler arası birlikte çalışabilirlik ile ilgili tek sorun, çerçevelerin DOM için kısıtlayıcı destek sunmasıdır. React bu çerçevelerden biridir ancak Refs aracılığıyla kaçış kapılarına izin verir ve React'teki Refs iyi bir geliştirici deneyimi sunmaz.
Lit ekibi, Lit bileşenlerinizi otomatik olarak ayrıştıracak ve referans kullanmanıza gerek kalmaması için bir React sarmalayıcı oluşturacak @lit-labs/react adlı deneysel bir proje üzerinde çalışıyor.
Ayrıca, Custom Elements Everywhere, hangi çerçevelerin ve kitaplıkların özel öğelerle iyi çalıştığını gösterir.
Birinci sınıf TypeScript desteği
Lit kodunuzun tamamını JavaScript'te yazmanız mümkün olsa da Lit, TypeScript'te yazılmıştır ve Lit ekibi, geliştiricilerin de TypeScript kullanmasını önerir.
Lit ekibi, lit-analyzer ve lit-plugin ile hem geliştirme hem de derleme sırasında TypeScript türü kontrolü ve IntelliSense'i Lit şablonlarına getiren projelerin sürdürülmesine yardımcı olmak için Lit topluluğuyla birlikte çalışıyor.


Geliştirici araçları tarayıcıya yerleşiktir.
Lit bileşenleri, DOM'daki HTML öğeleridir. Bu nedenle, bileşenlerinizi incelemek için tarayıcınıza herhangi bir araç veya uzantı yüklemeniz gerekmez.
Geliştirici araçlarını açıp bir öğe seçerek özelliklerini veya durumunu inceleyebilirsiniz.

Sunucu tarafı oluşturma (SSR) göz önünde bulundurularak oluşturulmuştur.
Lit 2, SSR desteği göz önünde bulundurularak geliştirilmiştir. Bu codelab yazılırken Lit ekibi henüz SSR araçlarını kararlı bir biçimde yayınlamamıştı ancak Lit ekibi, sunucu tarafında oluşturulan bileşenleri Google ürünlerinde kullanmaya başlamış ve React uygulamalarında SSR'yi test etmişti. Lit ekibi, bu araçları yakında GitHub'da herkese açık olarak yayınlamayı planlıyor.
Bu süre zarfında Lit ekibinin ilerleme durumunu buradan takip edebilirsiniz.
Düşük giriş maliyeti
Lit'i kullanmak için önemli bir taahhüt gerekmez. Lit'te bileşenler oluşturabilir ve bunları mevcut projenize ekleyebilirsiniz. Web bileşenleri diğer çerçevelerde çalıştığı için beğenmediğiniz kısımları varsa uygulamanın tamamını tek seferde dönüştürmeniz gerekmez.
Lit ile tam bir uygulama oluşturduysanız ve başka bir şeye geçmek istiyorsanız Bu durumda, mevcut Lit uygulamanızı yeni çerçevenize yerleştirebilir ve istediğiniz her şeyi yeni çerçevenin bileşenlerine taşıyabilirsiniz.
Ayrıca, birçok modern çerçeve, web bileşenlerinde çıkışı destekler. Bu nedenle, genellikle Lit öğesinin içine sığabilirler.
3. Playground'u kurma ve keşfetme
Bu codelab'i iki şekilde yapabilirsiniz:
- Bu işlemi tamamen çevrimiçi olarak tarayıcıda yapabilirsiniz.
- (Gelişmiş) VS Code kullanarak yerel makinenizde yapabilirsiniz.
Koda erişme
Bu codelab'de, Lit playground'a yönlendiren bağlantılar yer alacak. Örneğin:
Playground, tamamen tarayıcınızda çalışan bir kod korumalı alanıdır. TypeScript ve JavaScript dosyalarını derleyip çalıştırabilir, ayrıca içe aktarmaları otomatik olarak düğüm modüllerine çözebilir. Örneğin:
// 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ğitimin tamamını Lit Playground'da yapabilirsiniz. VS Code kullanıyorsanız bu kontrol noktalarını kullanarak herhangi bir adımın başlangıç kodunu indirebilir ve çalışmanızı kontrol edebilirsiniz.
Exploring the lit playground UI

Lit playground kullanıcı arayüzü ekran görüntüsünde, bu codelab'de kullanacağınız bölümler vurgulanmıştır.
- Dosya seçici. Artı düğmesini bulun...
- Dosya düzenleyici.
- Kod önizlemesi.
- Yeniden yükle düğmesi.
- İndir düğmesi.
VS Code kurulumu (Gelişmiş)
Bu VS Code kurulumunu kullanmanın avantajları şunlardır:
- Şablon türü kontrolü
- Şablon intellisense ve otomatik tamamlama
NPM, VS Code (lit-plugin eklentisiyle birlikte) zaten yüklüyse ve bu ortamı nasıl kullanacağınızı biliyorsanız aşağıdaki adımları uygulayarak bu projeleri indirip başlatabilirsiniz:
- İndir düğmesine basın.
- Tar dosyasının içeriğini bir dizine çıkarın.
- (TS ise) ES modüllerini ve ES2015+ değerini çıkaran bir quick tsconfig oluşturun.
- Çıplak modül tanımlayıcılarını çözümleyebilen bir geliştirme sunucusu yükleyin (Lit ekibi @web/dev-server'ı önerir)
- Bir örnek verelim
package.json
- Bir örnek verelim
- Geliştirme 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 --openkullanabilirsiniz)- Örnekteki
package.jsonkarakterini kullanıyorsanıznpm run devkarakterini kullanın.
- Örnekteki
4. JSX ve Şablon Oluşturma
Bu bölümde, Lit'te şablon oluşturmanın temellerini öğreneceksiniz.
JSX ve Lit şablonları
JSX, JavaScript'in söz dizimi uzantısıdır. React kullanıcılarının JavaScript kodlarında kolayca şablon yazmasına olanak tanır. Lit şablonları da benzer bir amaca hizmet eder: Bir bileşenin kullanıcı arayüzünü durumunun bir işlevi olarak ifade etmek.
Temel Söz Dizimi
React'te JSX hello world'ü şu şekilde 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 dahil edilen bir "ad" değişkeni vardır. Lit'te ş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ında, şablonlardaki birden fazla öğeyi gruplandırmak için React Fragment'e gerek olmadığını unutmayın.
Lit'te şablonlar, Lit'in adını aldığı yer olan html tagged template LITeral ile sarmalanır.
Şablon değerleri
Lit şablonları, TemplateResult olarak bilinen diğer Lit şablonlarını kabul edebilir. Örneğin, name öğesini italik (<i>) etiketleriyle ve etiketlenmiş bir şablon değişmez değeriyle (N.B.) sarmalayın. Tek tırnak karakteri (') değil, vurgu işareti karakteri (`) 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 TemplateResults, dizileri, dizeleri, diğer TemplateResults'leri ve yönergeleri kabul edebilir.
Bir 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 ve set oluşturma
JSX ve 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 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:
- Devre dışı bırakılanı tanımlanmış bir değişkene (bu durumda yanlış) ayarlar.
- Sınıfı
static-classartı bir değişkene (bu örnekte"static-class my-class") ayarlar. - Varsayılan bir değer ayarlar
Lit'te ş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çıp kapatmak için bir boole bağlaması eklenir.
Ardından, className yerine doğrudan class özelliğiyle bağlama vardır. 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 eklenebilir.
Son olarak, girişte value özelliği ayarlanır. React'in aksine, bu işlem giriş öğesinin 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 dizimidir.inputRef.toggleAttribute('attribute-name', booleanVar)etiketine eş değer.disabledkullanan öğeler için yararlıdır.disabled="false",inputElement.hasAttribute('disabled') === truenedeniyle DOM tarafından hâlâ doğru olarak okunur.
html`<my-element .property-name=${anyVar}>`;
.öneki, bir öğenin özelliğini ayarlamak için kullanılan bağlama söz dizimidir.inputRef.propertyName = anyVartutarına eşdeğer- Nesneler, diziler veya sınıflar gibi karmaşık verileri aktarmak için uygundur.
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çicileri ve querySelector'lar için uygundur.
İşleyici geçirme
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
Lit'te ş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
);
Lit örneğinde, click etkinliğine @click ile bir işleyici eklenmiştir.
Ardından, onChange yerine <input>'nin yerel input etkinliğine bağlama vardır. Bunun nedeni, yerel change etkinliğinin yalnızca blur üzerinde tetiklenmesidir (React bu etkinlikleri soyutlar).
Lit etkinlik işleyici söz dizimi
html`<my-element @event-name=${() => {...}}></my-element>`;
@öneki, bir etkinlik işleyicinin bağlama söz dizimidir.inputRef.addEventListener('event-name', ...)etiketine eş değer.- Yerel DOM etkinlik adlarını kullanır.
5. Bileşenler ve Öğeler
Bu bölümde, Lit 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ınmaktadır.
Sınıf Bileşenleri ve LitElement
React sınıf bileşeninin Lit'teki karşılığı LitElement'tir ve Lit'in "tepkisel özellikler" kavramı, React'in props ve state özelliklerinin 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, aşağıdakileri yapan bir React bileşeni var:
nameoluşturur.namepolitikasının varsayılan değerini boş dize ("") olarak ayarlar.nameadlı kullanıcının görevini"Elliott"adlı kullanıcıya yeniden atar.
LitElement'te bu işlemi şu şekilde yapabilirsiniz:
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);
HTML dosyasında ise:
<!-- 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 dair bir inceleme:
@property({type: String})
name = '';
- Herkese açık reaktif bir özellik tanımlar. Bu özellik, bileşeninizin genel API'sinin bir parçasıdır.
- Bir özelliği (varsayılan olarak) ve bileşeninizdeki bir mülkü kullanıma sunar.
- Bileşenin özelliğinin (dizeler) nasıl değere çevrileceğini tanımlar.
static get properties() {
return {
name: {type: String}
}
}
- Bu,
@propertyTS dekoratörüyle aynı işlevi görür ancak JavaScript'te yerel olarak çalışır.
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
- Bu işlev, herhangi bir tepkisel özellik her değiştirildiğinde çağrılır.
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
...
}
- Bu, bir HTML öğesi etiket adını bir sınıf tanımıyla ilişkilendirir.
- Custom Elements standardı nedeniyle, etiket adı tire (-) içermelidir.
- LitElement'teki
this, özel öğenin örneğini (bu durumda<welcome-banner>) ifade eder.
customElements.define('welcome-banner', WelcomeBanner);
- Bu,
@customElementTS dekoratörü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
Lit, JSX veya bir ön işlemci kullanmadığı için işlev bileşeninin bire bir yorumunu yapmaz. Ancak özellikleri alan ve bu özelliklere göre DOM 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
);
Lit'te bu ifade şu şekilde olur:
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 "Reactive Properties" (Tepkisel Ö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 özellikler iki varyantta sunulur:
Herkese açık tepkisel özellikler
// 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';
}
@propertytarafından tanımlanır.- React'in props ve state'ine benzer ancak değiştirilebilir
- Bileşenin tüketicileri tarafından erişilen ve ayarlanan genel 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';
}
@statetarafından tanımlanır.- React'in durumuna benzer ancak değiştirilebilir
- Genellikle bileşenden veya alt sınıflardan erişilen özel dahili durum
Yaşam döngüsü
Lit'in yaşam döngüsü, React'in yaşam döngüsüne oldukça benzer ancak bazı önemli 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';
}
}
- Edebi eşdeğeri de
constructor - Süper çağrıya herhangi bir şey iletmenize gerek yoktur.
- Şununla çağrıldı (tamamen kapsayıcı değildir):
document.createElementdocument.innerHTMLnew ComponentClass()- Sayfada yükseltilmemiş bir etiket adı varsa ve tanım
@customElementveyacustomElements.defineile yüklenip kaydedilmişse
- React'in
constructorişlevine benzer
render
// React
render() {
return <div>Hello World</div>
}
// Lit
render() {
return html`<div>Hello World</div>`;
}
- Edebi eşdeğeri de
render TemplateResultveyastringgibi oluşturulabilir tüm sonuçları döndürebilir.- React'e benzer şekilde,
render()saf bir işlev olmalıdır. createRenderRoot()hangi düğümü döndürürse ona göre 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üne ilk kez oluşturulduğunda çağrılır.
- Yalnızca öğe bağlandığında çağrılır.Örneğin, bu düğüm DOM ağacına eklenene kadar
document.createElement('my-component')aracılığıyla çağrılmaz. - Bu, bileşen tarafından oluşturulan DOM'un gerekli olduğu bileşen kurulumunu gerçekleştirmek için iyi bir yerdir.
- React'in aksine,
componentDidMountiçindeki reaktif özelliklerde yapılan değişiklikler, tarayıcı genellikle değişiklikleri aynı karede toplasa dafirstUpdatediçinde yeniden oluşturmaya neden olur. Bu değişiklikler kök DOM'a erişim gerektirmiyorsa genelliklewillUpdateiçine yerleştirilmelidir.
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.
- Özel öğeler, React bileşenlerinin aksine DOM'dan ayrıldığında yok edilmez ve bu nedenle birden çok kez "bağlanabilir"
firstUpdatedtekrar aranmayacak
- DOM'u yeniden başlatmak veya bağlantı kesildiğinde temizlenen etkinlik işleyicilerini 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);
}
}
- Lit.dev'deki eşdeğeri
updated(İngilizce "update" fiilinin geçmiş zaman hâli kullanılarak) - React'in aksine,
updatedilk oluşturma işleminde de çağrılır. - React'in
componentDidUpdateiş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,
disconnectedCallbackile benzerdir. - React bileşenlerinin aksine, özel öğeler DOM'dan ayrıldığında bileşen yok edilmez.
componentWillUnmount'nın aksine,disconnectedCallback, öğe ağaçtan kaldırıldıktan sonra çağrılır.- Kökün içindeki DOM, kökün alt ağacına bağlı kalır.
- Tarayıcının bileşeni çöp toplama işlemine tabi tutabilmesi için etkinlik işleyicileri ve bellek sızıntısı olan referansları temizlemek için kullanışlıdır.
Egzersiz
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 var:
- "Hello World! Şu an saat" deyip saati gösterir.
- Saat her saniye güncellenir.
- Söküldüğünde, tik işaretini ç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);
Ardından, bileşenin kullanıcıları date değerini doğrudan ayarlamayacağından date değerini ilk kullanıma hazırlayın ve @state ile dahili bir reaktif özellik olarak tanımlayın.
// 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);
Ardından, şablonu oluşturun.
// Lit (JS & TS)
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
Şimdi de onay işareti yöntemini uygulayın.
tick() {
this.date = new Date();
}
Ardından componentDidMount'nın uygulanması gelir. Yine, Lit analogu firstUpdated ve connectedCallback karışımıdır. Bu bileşen söz konusu olduğunda, tick işlevini setInterval ile çağırmak için kök içindeki DOM'a erişim gerekmez. Ayrıca, öğe belge ağacından kaldırıldığında aralık temizlenir. Bu nedenle, öğe yeniden eklenirse aralığın tekrar başlatılması gerekir. Bu nedenle, connectedCallback bu durumda 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, öğe belge ağacından ayrıldıktan sonra tikin yürütülmemesi için aralığı temizleyin.
// Lit (TS & JS)
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
Tüm bilgiler bir araya getirildiğinde şu şekilde görünür:
// 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. Dikkat çekici girişler
Bu bölümde, React Hook kavramlarını Lit'e nasıl çevireceğinizi öğreneceksiniz.
React kancalarıyla ilgili kavramlar
React kancaları, işlev bileşenlerinin duruma "bağlanmasını" sağlar. Bunun çeşitli avantajları vardır.
- Durumlu mantığın yeniden kullanılmasını kolaylaştırır.
- Bir bileşeni daha küçük işlevlere ayırmaya yardımcı olma
Ayrıca, işlev tabanlı bileşenlere odaklanma, React'in sınıf tabanlı söz dizimiyle ilgili belirli sorunları (ör. aşağıdakiler) ele almıştır:
props'yıconstructor'densuper'ye aktarmakconstructor- içindeki özelliklerin düzensiz başlatılması
- Bu, o sırada React ekibi tarafından belirtilen bir nedendi ancak ES2019 ile çözüldü.
thisartık bileşene başvurmadığı için oluşan sorunlar
Lit'teki React kancası kavramları
Bileşenler ve Özellikler 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 ana 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ıyor?
constructorişlevi bağımsız değişken almaz- Tüm
@eventbağlamalarıthisile otomatik olarak bağlanır. thisvakaların büyük çoğunluğunda özel öğenin referansını ifade eder.- Sınıf özellikleri artık sınıf üyeleri olarak örneklenebilir. Bu, oluşturucu tabanlı uygulamaları temizler.
Reaktif denetleyiciler
Hooks'un temelindeki kavramlar, Lit'te reaktif denetleyiciler olarak bulunur. Tepkisel denetleyici kalıpları, durum bilgisi içeren mantığın paylaşılmasına, bileşenlerin daha küçük ve modüler parçalara ayrılmasına ve bir öğenin güncelleme yaşam döngüsüne bağlanmasına olanak tanır.
Tepkisel 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ü:
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 öğeye eklediğinizde, denetleyicinin yaşam döngüsü ana öğenin 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:
- "Hello World! Şu an saat" deyip saati gösterir.
- Saat her saniye güncellenir.
- Söküldüğünde, tik işaretini çağıran aralığı temizler.
Bileşen iskeleti oluşturma
Öncelikle bileşen sınıfı bildirimini yaparak 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'ya geçin ve ClockController için bir sınıf oluşturup constructor'ı ayarlayı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() {
}
}
Reaktif denetleyici, ReactiveController arayüzünü paylaştığı sürece herhangi bir şekilde oluşturulabilir. Ancak Lit ekibi, çoğu temel durumda denetleyiciyi başlatmak için gereken diğer özelliklerin yanı sıra ReactiveControllerHost arayüzünü de alabilen bir constructor ile sınıf kullanmayı tercih eder.
Şimdi React yaşam döngüsü geri çağırmalarını denetleyici geri çağırmalarına çevirmeniz gerekiyor. Kısaca:
componentDidMount- LitElement'in
connectedCallback - Kumandanın
hostConnected
- LitElement'in
ComponentWillUnmount- LitElement'in
disconnectedCallback - Denetleyicinin
hostDisconnected
- LitElement'in
React yaşam döngüsünü Lit yaşam döngüsüne çevirme hakkında daha fazla bilgi için State & Lifecycle (Durum ve Yaşam Döngüsü) bölümüne bakın.
Ardından, hostConnected geri çağırma ve tick yöntemlerini uygulayın ve hostDisconnected içindeki aralığı Durum ve Yaşam Döngüsü bölümündeki örnekte olduğu 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);
}
}
Kumandayı kullanma
Saat denetleyicisini kullanmak için denetleyiciyi içe aktarın ve bileşeni index.ts veya index.js'da 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) referans ileterek denetleyiciyi örneklendirmeniz ve ardından render yönteminde denetleyiciyi kullanmanız gerekir.
Kumandada yeniden oluşturmayı tetikleme
Saatin gösterildiğini ancak güncellenmediğini fark edin. Bunun nedeni, kumandanın tarihi her saniye ayarlamasına rağmen ana makinenin güncellemeyi yapmamasıdır. Bunun nedeni, date artık bileşende değil, ClockController sınıfında değişiyor olmasıdır. Bu, kumandada date ayarlandıktan sonra ana makineye güncelleme yaşam döngüsünü host.requestUpdate() ile çalıştırması gerektiğinin söylenmesi gerektiği anlamına gelir.
// Lit (TS & JS) - clock.ts / clock.js
private tick() {
this.date = new Date();
this.host.requestUpdate();
}
Artık saat işlemeye başlamalıdır.
Kancalarla ilgili yaygın kullanım alanlarının daha ayrıntılı bir karşılaştırması için lütfen İleri Düzey Konular - Kancalar bölümüne bakın.
8. Çocuklar
Bu bölümde, Lit'te çocukları yönetmek için yuvaları nasıl kullanacağınızı öğreneceksiniz.
Slotlar ve Çocuklar
Yuvalar, bileşenleri iç içe yerleştirmenize olanak tanıyarak birleştirme işlemini mümkün kılar.
React'te alt öğeler, props aracılığıyla devralınır. Varsayılan yuva props.children'dır ve render işlevi, varsayılan yuvanın konumunu 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 çocuklar, oluşturma işlevinde yuva öğeleriyle oluşturulur. Çocukların, React'te olduğu gibi aynı şekilde devralınmadığını unutmayın. Lit'te çocuklar, yuvalara eklenmiş HTMLElements'tir. Bu ek, Projeksiyon olarak adlandırılır.
@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 prop 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 yer oluşturur. name özelliğiyle birden fazla yuva tanımlandı: <slot name="slot-name">. Bu sayede çocuklar, hangi aralığa atanacaklarını belirleyebilir.
@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 Slot İçeriği
Yuvalar, bu yuvaya yansıtılan düğüm olmadığında alt ağaçlarını gösterir. Düğümler bir yuvaya yansıtıldığında, bu yuva 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>
`;
}
}
Çocukları aralıklara atama
React'te alt öğeler, bir bileşenin özellikleri aracılığıyla yuvalara 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>}
/>
);
};
Lit'te çocuklar, 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 bir yuva (ör. <slot>) yoksa ve özel öğenin alt öğelerinin slot özelliğiyle (ör. <div slot="foo">) eşleşen bir name özelliği olan bir yuva (ör. <slot name="foo">) yoksa bu düğüm yansıtılmaz ve görüntülenmez.
9. Refs
Geliştiricilerin zaman zaman bir HTMLElement'in API'sine erişmesi gerekebilir.
Bu bölümde, Lit'te öğe referanslarını nasıl edineceğinizi öğreneceksiniz.
React Referansları
Bir React bileşeni, çağrıldığında sanal DOM oluşturan bir dizi işlev çağrısına dönüştürülür. Bu sanal DOM, ReactDOM tarafından yorumlanır ve HTMLElements öğelerini oluşturur.
React'te Refs, oluşturulan bir HTMLElement'i içerecek şekilde bellekte ayrılan 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, React bileşeni şunları yapar:
- Boş bir metin girişi ve metin içeren bir düğme oluşturun.
- Düğme tıklandığında girişe odaklanma
İlk oluşturma işleminden sonra React, inputRef.current öğesini ref özelliği aracılığıyla oluşturulan HTMLInputElement olarak ayarlar.
@query ile "Referanslar"ı aydınlatma
Lit, tarayıcıya yakın bir şekilde çalışır ve yerel tarayıcı özelliklerinin üzerinde çok ince bir soyutlama katmanı oluşturur.
Lit'teki refs öğesinin React'teki karşılığı, @query ve @queryAll dekoratörleri tarafından döndürülen HTMLElement'dir.
@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:
@querydekoratörünü kullanarakMyElementüzerinde bir özellik tanımlar (HTMLInputElementiçin alıcı oluşturur).onButtonClickadlı bir tıklama etkinliği geri çağırma işlevini bildirir ve ekler.- Düğme tıklama işleminde girişe odaklanır.
JavaScript'te @query ve @queryAll dekoratörleri sırasıyla querySelector ve querySelectorAll işlemlerini gerçekleştirir. Bu, @query('input') inputEl!: HTMLInputElement; öğesinin JavaScript eşdeğeridir.
get inputEl() {
return this.renderRoot.querySelector('input');
}
Lit bileşeni, render yönteminin şablonunu my-element'nin köküne uyguladıktan sonra @query dekoratörü, inputEl'nin oluşturma kökünde bulunan ilk input öğesini döndürmesine olanak tanır. @query belirtilen öğeyi bulamazsa null değerini döndürür.
Render kökünde birden fazla input öğesi varsa @queryAll, düğümlerin listesini döndürür.
10. Aracılık 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 malzemeleri aracılığıyla durum bilgisi verir. Çocuklar, sahne malzemelerinde bulunan geri aramalar 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 şunları yapar:
props.stepdeğerine göre bir etiket oluşturur.- Etiketi +step veya -step olan bir düğme oluşturur.
- Tıklama sırasında
props.addToCounterişleviniprops.stepbağımsız değişkeniyle çağırarak üst bileşeni günceller.
Geri çağırmaları Lit'te iletmek mümkün olsa da geleneksel kalıplar farklıdır. Yukarıdaki örnekteki React bileşeni, aşağıdaki örnekte Lit 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 oluşturun
step - Tıklama işleminde öğenin
stepdeğerini taşıyanupdate-counteradlı özel bir etkinlik gönderme
Tarayıcı etkinlikleri, alt öğelerden üst öğelere doğru yayılır. Etkinlikler, çocukların etkileşim etkinliklerini ve durum değişikliklerini yayınlamasına olanak tanır. React temelde durumu ters yönde iletir. Bu nedenle, React bileşenlerinin etkinlikleri Lit bileşenleriyle aynı şekilde göndermesi ve dinlemesi yaygın değildir.
Durum bilgili bileşenler
React'te durumu yönetmek için kancalar kullanmak yaygın bir uygulamadır. MyCounter bileşeni, CounterButton bileşeni yeniden kullanılarak oluşturulabilir. addToCounter öğesinin, CounterButton öğesinin her iki örneğine de 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 şunlar yapılmaktadır:
countdurumu oluşturur.- Bir
countdurumuna sayı ekleyen bir geri arama oluşturur. CounterButton, her tıklamadacountöğesinistepile güncellemek içinaddToCounterkullanır.
MyCounter benzer bir uygulama Lit'te de yapılabilir. addToCounter değerinin counter-button değerine aktarılmadığına dikkat edin. Bunun yerine geri çağırma, ü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 şunlar yapılmaktadır:
- Değer değiştiğinde bileşeni güncelleyecek
countadlı reaktif bir özellik oluşturur. addToCountergeri çağırma işlevini@update-counteretkinlik işleyicisine bağlar.count,update-counteretkinliğinindetail.stepbölümünde bulunan değer eklenerek güncellenir.stepözelliği aracılığıylacounter-button'nınstepdeğerini ayarlar.
Lit'te değişiklikleri üst öğelerden alt öğelere yayınlamak için reaktif özellikler kullanmak daha yaygındır. Benzer şekilde, ayrıntıları alttan yukarıya doğru aktarmak için tarayıcının etkinlik sistemini kullanmak da iyi bir uygulamadır.
Bu yaklaşım, en iyi uygulamalara uygundur ve Lit'in web bileşenleri için platformlar arası destek sağlama hedefine bağlıdır.
11. Stil
Bu bölümde Lit'te stil oluşturma hakkında bilgi edineceksiniz.
Stil
Lit, öğeleri stilize etmek için birden fazla yolun yanı sıra yerleşik bir çözüm sunar.
Satır içi stiller
Lit, 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 border-color.js'dan turuncu metne bir kenarlık içe aktarıp 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 can sıkıcı olabilir. Bu nedenle Lit, bu konuda yardımcı olacak bir yönerge sunar.
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 örnekte şunlar yapılmaktadır:
- Kenarlıklı ve renk seçicili bir
h1gösterir. border-colordeğerini renk seçiciden alınan 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 dizimine sahiptir.
CSSResult
Bileşenleri stilize etmek için önerilen yöntem, css etiketli şablon değişmezini 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 şunlar yapılmaktadır:
- Bağlama içeren bir CSS etiketli şablon değişmezi bildirir.
- Kimlikleri olan iki
h1öğesinin renklerini ayarlar.
css şablon etiketini kullanmanın avantajları:
- Sınıf başına bir kez ayrıştırılır, örnek başına ayrıştırılmaz.
- Modülün yeniden kullanılabilirliği göz önünde bulundurularak uygulanır.
- Stilleri kolayca kendi dosyalarına ayırabilir.
- CSS özel özellikleri polyfill'iyle uyumludur.
Ayrıca, index.html içindeki <style> etiketine dikkat edin:
<!-- index.html -->
<style>
h1 {
color: red !important;
}
</style>
Lit, bileşenlerinizin stillerini kökleriyle sınırlandırır. Bu, stillerin sızmayacağı anlamına gelir. Lit ekibi, stilleri bileşenlere aktarmak için CSS özel özelliklerinin kullanılmasını önerir. Bu özellikler, Lit stil kapsamına girebilir.
Stil Etiketleri
Şablonlarınıza <style> etiketlerini satır içi olarak da ekleyebilirsiniz. Tarayıcı bu stil etiketlerinin tekilleştirmesini yapar ancak bunları şablonlarınıza yerleştirdiğinizde, css etiketli şablonda olduğu gibi sınıf başına değil, bileşen örneği başına ayrıştırılırlar. Ayrıca, tarayıcıda CSSResult öğelerinin yinelenen kopyalarını kaldırma işlemi çok daha hızlıdır.
Bağlantı Etiketleri
Şablonunuzda <link rel="stylesheet"> kullanmak da stiller için bir olasılıktır ancak bu da, stillendirilmemiş içeriklerin ilk yanıp sönmesine (FOUC) neden olabileceğinden önerilmez.
12. İleri Düzey Konular (isteğe bağlı)
JSX ve Şablon Oluşturma
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 değişmez spesifikasyonuna özgü performans özelliklerinden yararlanır. Etiketli şablon değişmezleri, kendilerine eklenmiş etiket işlevlerine sahip şablon değişmez dizelerdir.
Şablon değişmezine bir örnek:
const str = 'string';
console.log(`This is a template literal ${str}`);
Etiketlenmiş şablon değişmezine bir ö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, etiketlenmiş bir şablon değişmez değerinin çağrılmasını döndürür.
Lit'teki performansın büyük bir kısmı, etiket işlevine iletilen dize dizilerinin aynı işaretçiye sahip olmasından kaynaklanır (ikinci console.log'da gösterildiği gibi). Tarayıcı, aynı şablon değişmezini (yani AST'deki aynı konumda) 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 işlemleri, çalışma zamanı farklılaştırma yükü olmadan bu özelliklerden yararlanabilir.
Etiketlenmiş şablon değişmezlerinin bu yerleşik tarayıcı davranışı, Lit'e önemli bir performans avantajı sağlar. Geleneksel sanal DOM'ların çoğu işlerinin büyük bir kısmını JavaScript'te yapar. Ancak etiketlenmiş şablon değişmezleri, farklılıkların çoğunu tarayıcının C++'ında yapar.
React veya Preact ile HTML etiketli şablon değişmezlerini kullanmaya başlamak istiyorsanız Lit ekibi htm kitaplığını önerir.
Ancak Google Codelabs sitesinde ve çeşitli online kod düzenleyicilerde olduğu gibi, etiketlenmiş şablon hazır değer 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, VS Code eklentisi olan lit-plugin gibi projeleri sürdürmek için toplulukla da çok yakın bir şekilde çalışır. Bu eklenti, Lit projelerinize söz dizimi vurgulama, tür kontrolü ve IntelliSense özellikleri ekler.
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 ön işlemci (genellikle Babel aracılığıyla) kullanır.
Örneğin, Babel şu ifadeyi dönüştürür:
const element = <div className="title">Hello World!</div>;
ReactDOM.render(element, mountNode);
şuna dönüştürülür:
const element = React.createElement('div', {className: 'title'}, 'Hello World!');
ReactDOM.render(element, mountNode);
React DOM, React çıkışını alıp gerçek DOM'a (özellikler, nitelikler, etkinlik işleyicileri vb.) çevirir.
Lit-html, tarayıcıda dönüştürme veya ön işlemci olmadan çalıştırılabilen etiketlenmiş şablon değişmezleri kullanır. Bu nedenle, Lit'i kullanmaya başlamak için yalnızca bir HTML dosyası, bir ES modülü komut dosyası ve bir sunucuya ihtiyacınız vardır. Tamamen tarayıcıda ç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 sistemi olan lit-html, geleneksel bir sanal DOM yerine doğrudan DOM API'yi kullandığından Lit 2'nin boyutu, React (2,8 KB) + react-dom'un (39,4 KB) 40 KB'lık küçültülmüş ve gzip'lenmiş boyutuna kıyasla 5 KB'tan daha küçüktür.
Etkinlikler
React, yapay etkinlik sistemi kullanır. Bu nedenle, react-dom her bileşende kullanılacak her etkinliği tanımlamalı ve her düğüm türü için camelCase etkinlik işleyici eşdeğeri sağlamalıdır. Sonuç olarak, JSX'te özel bir etkinlik için etkinlik işleyici tanımlama yöntemi yoktur ve geliştiricilerin ref kullanıp ardından zorunlu olarak bir işleyici uygulaması gerekir. Bu durum, React'i dikkate almayan kitaplıkları entegre ederken yetersiz bir geliştirici deneyimine yol açar ve React'e özgü bir sarmalayıcı yazılmasına neden olur.
Lit-html, doğrudan DOM'a erişir ve yerel etkinlikleri kullanır. Bu nedenle, etkinlik işleyicileri eklemek @event-name=${eventNameListener} kadar kolaydır. Bu sayede, etkinlik dinleyicileri ekleme ve etkinlikleri tetikleme için daha az çalışma zamanı ayrıştırması yapılır.
Bileşenler ve Öğeler
React bileşenleri ve özel öğeler
LitElement, bileşenlerini paketlemek için özel öğeler kullanır. Özel öğeler, bileşenleştirme söz konusu olduğunda React bileşenleri arasında bazı ödünler verilmesine neden olur (durum ve yaşam döngüsü hakkında daha fazla bilgiyi Durum ve Yaşam Döngüsü bölümünde bulabilirsiniz).
Özel öğelerin bileşen sistemi olarak bazı avantajları:
- Tarayıcıya özeldir ve herhangi bir araç gerektirmez.
innerHTMLvedocument.createElement'denquerySelector'ye kadar her tarayıcı API'sine uyum sağlar.- Genellikle çerçeveler arasında kullanılabilir.
customElements.defineile geç kaydedilebilir ve DOM "hydrate" edilebilir.
Ö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 yoktur).
- Kapatma etiketi
- içermelidir.
- Not: Tarayıcı satıcıları, geliştiricilerin rahatlığına rağmen kendi kendini kapatan etiket spesifikasyonundan pişmanlık duymaktadır. Bu nedenle, daha yeni spesifikasyonlar kendi kendini kapatan etiketleri içermez.
- DOM ağacına, düzen sorunlarına neden olabilecek ekstra bir düğüm ekler.
- JavaScript aracılığıyla kaydedilmelidir.
Lit, tarayıcıya yerleştirilmiş özel öğeler olduğu için özel bir öğe sistemi yerine özel öğeleri tercih etti. Lit ekibi, çerçeveler arası avantajların bileşen soyutlama katmanının sağladığı avantajlardan daha fazla olduğuna inanıyor. Hatta Lit ekibinin lit-ssr alanındaki çalışmaları, JavaScript kaydıyla ilgili temel sorunların üstesinden gelmeyi başardı. Ayrıca GitHub gibi bazı şirketler, sayfaları isteğe bağlı özelliklerle kademeli olarak geliştirmek için özel öğe tembel kaydından yararlanır.
Özel öğelere veri aktarma
Özel öğelerle ilgili yaygın bir yanlış kanı, verilerin yalnızca dizeler olarak iletilebileceğidir. Bu yanlış anlaşılma, büyük olasılıkla öğe özelliklerinin yalnızca dizeler olarak yazılabilmesinden kaynaklanmaktadır. Lit'in dize özelliklerini tanımlı türlerine dönüştürdüğü doğru olsa da özel öğeler, karmaşık verileri özellik olarak da kabul edebilir.
Örneğin, aşağıdaki LitElement tanımı verildiğinde:
// 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üren temel bir reaktif özellik num tanımlanır. Ardından, Lit'in özellik işlemeyi devre dışı bırakan attribute:false ile karmaşık bir veri yapısı oluşturulur.
Bu özel öğeye veri iletmek için aşağıdaki yöntemi kullanın:
<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 React Yaşam Döngüsü Geri Çağırma Yöntemleri
static getDerivedStateFromProps
Lit'te props ve state aynı sınıf özellikleri olduğundan eşdeğeri yoktur.
shouldComponentUpdate
- Eşdeğer birim
shouldUpdate - React'in aksine ilk oluşturma işleminde çağrılır.
- React'in
shouldComponentUpdateişlevine benzer
getSnapshotBeforeUpdate
Lit'te getSnapshotBeforeUpdate, hem update hem de willUpdate ile benzerdir.
willUpdate
updatetarihinden önce arandıgetSnapshotBeforeUpdate'dan farklı olarakwillUpdate,render'dan önce çağrılır.willUpdateiçindeki tepkisel özelliklerde yapılan değişiklikler, güncelleme döngüsünü yeniden tetiklemez.- Diğer özelliklere bağlı olan ve güncelleme sürecinin 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'a erişilmesi önerilmez.
update
willUpdatetarihinden sonra arandıgetSnapshotBeforeUpdate'dan farklı olarakupdate,render'dan önce çağrılır.updateiçindeki tepkisel ö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 çıktı DOM'a aktarılmadan önce bileşeni çevreleyen DOM'dan bilgi almak için iyi bir yerdir.
- Bu yöntem, SSR'de sunucuda çağrılmaz.
Diğer Lit Yaşam Döngüsü Geri Çağırma Yöntemleri
React'te benzeri olmadığı için önceki bölümde bahsedilmeyen birkaç yaşam döngüsü geri çağırması vardır. Bunları şöyle sıralayabiliriz:
attributeChangedCallback
Öğenin observedAttributes özelliklerinden 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 bir özellik API'si sağlamak üzere Lit tarafından arka planda uygulanır.
adoptedCallback
Bileşen yeni bir dokümana taşındığında (ör. HTMLTemplateElement öğesinin documentFragment öğesinden ana document öğesine) çağrılır. Bu geri çağırma, özel öğeler spesifikasyonunun da bir parçasıdır ve yalnızca bileşen belgeleri değiştirdiğinde 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ştirmenize yardımcı olmak 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 öğe güncellemeyi tamamladığında çözülen bir Promise'dır. Ö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 öğesinin ne zaman çözümleneceğini özelleştirmek için geçersiz kılınması gereken bir yöntemdir. Bu durum, bir bileşen alt bileşeni oluşturduğunda ve oluşturma döngülerinin senkronize olması gerektiğinde yaygındır. Örneğin:
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öntemlerini çağıran yöntemdir. Bu, genellikle senkronize güncellemenin yapılması gereken veya özel planlamanın kullanıldığı nadir durumlar dışında gerekli değildir.
hasUpdated
Bu özellik, bileşen en az bir kez güncellendiyse true olur.
isConnected
Özel öğeler spesifikasyonunun bir parçası olan bu özellik, öğe şu anda ana belge ağacına eklenmişse true olur.
Lit Güncelleme 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ı
Güncelleme Öncesi

requestUpdate tarihinden sonra planlanmış bir güncelleme bekleniyor.
Güncelle

Güncelleme sonrası

Dikkat çekici girişler
Neden dikkat çekici girişler?
Hooks, durum gerektiren basit işlev bileşeni kullanım alanları için React'e dahil edildi. Kancalı fonksiyon bileşenleri, birçok basit durumda sınıf bileşeni karşılıklarından çok daha basit ve okunabilir olur. Ancak, eşzamansız durum güncellemeleri sunmanın yanı sıra kancalar veya efektler arasında veri aktarırken kanca kalıbı yeterli olmayabilir ve reaktif denetleyiciler gibi sınıfa dayalı bir çözüm daha iyi sonuç verebilir.
API isteği 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şlev bileşenini ele alalım:
index.tsx- Metni oluşturur
useAPIadlı kullanıcının yanıtını oluşturur.- Kullanıcı kimliği + kullanıcı adı
- Hata Mesajı
- 11. kullanıcıya ulaşıldığında 404 hatası (tasarım gereği)
- 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.tsxuseApiözel kancasını tanımlar.- Bir API'den kullanıcı nesnesini eşzamansız olarak getirme
- Yayınlar:
- Kullanıcı adı
- Getirme işleminin yüklenip yüklenmediği
- Hata mesajları
- Getirme işlemini iptal etmek için geri çağırma
- Sökülürse devam eden getirme işlemlerini durdurur.
Lit + Reactive Controller uygulamasını burada bulabilirsiniz.
Çıkarımlar:
- Reactive Controllers, en çok özel kancalara benzer.
- Geri çağırma işlevleri ve efektler arasında oluşturulmayan verileri aktarma
- React,
useRefileuseEffectveuseCallbackarasında veri aktarmak için kullanılır. - Lit, özel bir sınıf özelliği kullanır
- React, aslında özel bir sınıf özelliğinin davranışını taklit eder.
- React,
Ayrıca, kancalarla React işlev bileşeni söz dizimini ancak Lit'in derlemesiz ortamını kullanmak istiyorsanız Lit ekibi Haunted kitaplığını kullanmanızı önerir.
Çocuklar
Varsayılan yuva
HTML öğelerine slot özelliği verilmediğinde, bu öğeler varsayılan adsız yuvaya atanır. Aşağıdaki örnekte, MyApp adlı bir yuvaya bir paragraf yerleştirir. Diğer paragraf varsayılan olarak adsız alana yerleştirilir.
@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 slotchange etkinliği tetiklenir. Bir Lit bileşeni, bir slotchange etkinliğine etkinlik dinleyici bağlayabilir. Aşağıdaki örnekte, shadowRoot içinde bulunan ilk yuvanın assignedNodes değeri 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>
`;
}
}
Refs
Referans oluşturma
Hem Lit hem de React, render işlevleri çağrıldıktan sonra bir HTMLElement'e referans verir. Ancak React ve Lit'in, daha sonra Lit @query dekoratörü veya React Referansı aracılığıyla döndürülen DOM'u nasıl oluşturduğunu incelemek faydalı olacaktır.
React, HTMLElements değil React Components oluşturan işlevsel bir işlem hattıdır. Bir Ref, bir HTMLElement oluşturulmadan önce bildirildiği için bellekte bir alan ayrılır. Bu nedenle, gerçek DOM öğesi henüz oluşturulmadığı (veya oluşturulmadığı) için null, Ref'in başlangıç değeri olarak görünür.useRef(null)
ReactDOM, bir React bileşenini HTMLElement'e dönüştürdükten sonra ReactComponent'te ref adlı bir özellik arar. Varsa ReactDOM, HTMLElement'ın referansını ref.current içine yerleştirir.
LitElement, arka planda Template Element oluşturmak için lit-html'deki html şablon etiketi işlevini kullanır. LitElement, oluşturma işleminden sonra şablonun içeriğini özel bir öğenin gölge DOM'una damgalar. Gölge DOM, bir gölge kökü tarafından kapsanan, kapsamlı bir DOM ağacıdır. @query dekoratörü, daha sonra mülk için bir alıcı oluşturur. Bu alıcı, kapsamlı kökte temelde bir this.shadowRoot.querySelector işlemi gerçekleştirir.
Birden Çok Öğeyi Sorgulama
Aşağıdaki örnekte, @queryAll dekoratörü, gölge kökündeki 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, aynı amaçla bir getter tanımlanabilir:
get paragraphs() {
return this.renderRoot.querySelectorAll('p');
}
Sorguyu Değiştiren Öğeler
@queryAsync dekoratörü, başka bir öğe özelliğinin 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 bir paragraf öğesi yalnızca renderParagraph rastgele bir tek sayı oluşturduğunda oluşturulur. @queryAsync yönergesi, ilk paragraf kullanılabilir olduğunda çözümlenecek 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()}
`;
}
}
Aracılık durumu
React'te durumun aracılığını React'in kendisi yaptığı için geri çağırma işlevlerinin kullanılması gelenekseldir. React, öğeler tarafından sağlanan duruma güvenmemek için elinden geleni yapar. DOM, yalnızca oluşturma sürecinin 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ı içinde de bulunan tüm kitaplıklar Lit tarafından kullanılabilir. Lit'teki mevcut durum yönetimi sistemlerinden yararlanmak için birçok harika kitaplık oluşturuldu.
Vaadin'in, Lit bileşeninde Redux'tan nasıl yararlanılacağını açıklayan bir serisini burada bulabilirsiniz.
Büyük ölçekli bir sitenin Lit'te MobX'ten nasıl yararlanabileceğini görmek için Adobe'un lit-mobx'ine göz atın.
Ayrıca, geliştiricilerin GraphQL'i 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 çoğu durum yönetimi çözümü Lit bileşeninde kullanılabilir.
Stil
Shadow DOM
Lit, stilleri ve DOM'u bir özel öğe içinde doğal olarak kapsamak için gölge DOM'u kullanır. Gölge kökler, ana belge ağacından ayrı bir gölge ağacı oluşturur. Bu, çoğu stilin bu dokümanla sınırlı olduğu anlamına gelir. Renk ve yazı tipiyle ilgili diğer stiller gibi bazı stiller sızabilir.
Shadow DOM, CSS spesifikasyonuna yeni kavramlar ve seçiciler de ekler:
: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
Geleneksel temalandırma, genellikle yukarıdan aşağıya stil etiketi yaklaşımları olduğundan gölge kökler bu konuda biraz zorluk çıkarır. Gölge DOM kullanan Web Bileşenleri ile temalandırmayı ele almanın geleneksel yolu, CSS Özel Özellikleri aracılığıyla bir stil API'si kullanıma sunmaktır. Örneğin, Materyal Tasarım'da kullanılan bir desen:
.mdc-textfield-outline {
border-color: var(--mdc-theme-primary, /* default value */ #...);
}
.mdc-textfield--input {
caret-color: var(--mdc-theme-primary, #...);
}
Kullanıcı daha sonra ö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şturma zorunluysa ve stilleri kullanıma sunamıyorsanız createRenderRoot'yı geçersiz kılarak this döndürecek şekilde ayarlayarak Shadow DOM'u devre dışı bırakabilirsiniz. Bu durumda, bileşenlerinizin şablonu, özel öğeye eklenmiş bir gölge köküne değil, özel öğenin kendisine oluşturulur. Bu durumda stil kapsülleme, DOM kapsülleme ve yuvaları kaybedersiniz.
Üretim
IE 11
IE 11 gibi eski tarayıcıları desteklemeniz gerekiyorsa yaklaşık 33 KB'lık bazı polyfill'leri yüklemeniz gerekir. Daha fazla bilgiye buradan ulaşabilirsiniz.
Koşullu paketler
Lit ekibi, biri IE 11 için, diğeri modern tarayıcılar için olmak üzere iki farklı paket sunmanızı önerir. Bu durumun çeşitli avantajları vardır:
- ES 6'ya hizmet vermek daha hızlıdır ve müşterilerinizin çoğu için uygundur.
- Transpile edilmiş ES 5, paket boyutunu önemli ölçüde artırıyor
- Koşullu paketler, iki dünyanın en iyi özelliklerini bir araya getirir.
- IE 11 desteği
- Modern tarayıcılarda yavaşlama olmaz
Koşullu olarak sunulan bir paket oluşturma hakkında daha fazla bilgiyi belgeler sitemizde burada bulabilirsiniz.