React Geliştiricileri için Edebiyat

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.

Küçültülmüş ve KB cinsinden sıkıştırılmış paket boyutunun çubuk grafiği. Lit çubuğu 5 KB, React + React DOM ise 42,2 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.

Parlaklığı milisaniye cinsinden React ile karşılaştıran performansın gruplandırılmış çubuk grafiği (düşük olması iyidir)

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.

Belirtilen boole değerini bir sayıya ayarlamayla ilgili yanlış tür kontrolünü gösteren bir IDE ekran görüntüsü

Bilgiye yönelik önerileri gösteren entegre geliştirme ortamının ekran görüntüsü

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.

Chrome geliştirici araçlarının $0 değerinin <mwc-textfield>, $0.value değerinin hello world, $0.outlined sonucunun, ve {$0} değerinin mülk genişletmesinin döndürüldüğünü gösteren resmi

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

Dosya seçici sekme çubuğu Bölüm 1, Kod düzenleme bölümü Bölüm 2, çıkış önizlemesi Bölüm 3 ve önizleme yeniden yükle düğmesi Bölüm 4 olarak etiketlenmiştir

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.

  1. Dosya seçici. Artı düğmesine dikkat edin...
  2. Dosya düzenleyici.
  3. Kod önizlemesi.
  4. Yeniden yükle düğmesi.
  5. İ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)
  • 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ız npm 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 dizimidir
  • inputRef.toggleAttribute('attribute-name', booleanVar) etiketine eşdeğer
  • disabled="false", DOM tarafından doğru olarak okunmaya devam ettiğinden inputElement.hasAttribute('disabled') === true için disabled 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 dizimidir
  • inputRef.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 veya customElements.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 veya string 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 olarak ShadowRoot)

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ılan componentDidMount 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 genellikle willUpdate 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 aksine disconnectedCallback, öğ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ı:

  • propsconstructor'dan super'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
  • ComponentWillUnmount
    • LitElement'ın disconnectedCallback cihazına
    • Denetleyicinin hostDisconnected

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 kullanarak MyElement ü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 ile props.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şıyan update-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>&Sigma;: {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ıklamada count değerini step değerine göre güncellemek için addToCounter 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>&Sigma; ${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ğlar
  • update-counter etkinliğinin detail.step parametresinde bulunan değeri ekleyerek count parametresini günceller.
  • step özelliği aracılığıyla counter-button öğesinin step 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.

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 ve document.createElement ile querySelector 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 aksine willUpdate, 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 aksine update, 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

Geri çağırma adlarına sahip düğümlerin yönlendirilmiş bir döngüsel grafiği. requestUpdate kurucusu. @property yerine Property Setter. attributeChangedCallback yerine Property Setter. Mülk Setter değeri hasChanged. hasChanged olarak requestUpdate olarak değiştirildi. requestUpdate, bir sonraki güncelleme yaşam döngüsü grafiğini işaret eder.

requestUpdate tarihinden sonra planlanmış bir güncelleme beklenir.

Güncelle

Geri çağırma adlarına sahip düğümlerin yönlendirilmiş bir döngüsel grafiği. Güncelleme öncesi yaşam döngüsü noktalarını gösteren önceki resimdeki ok. &quot;PerformUpdate&quot;e, &quot;postUpdate.&quot; &quot;/&quot; öğesinin güncel olması için gerekli güncellemeleri ekleyin. Güncelleme için güncelleyin. Güncellemek için güncelleyin. Güncelleme sonrası hem oluşturma hem de bir sonraki güncelleme sonrası yaşam döngüsü grafiğine geçin. Oluşturma sırasında bir sonraki güncelleme sonrası yaşam döngüsü grafiğine işaret eder.

Güncelleme sonrası

Geri çağırma adlarına sahip düğümlerden oluşan bir yönlendirilmiş düz ağaç. Güncelleme yaşam döngüsü noktalarının önceki resmindeki ok ilk Güncellendi. İlk güncellendi olarak güncellendi. Güncelleme tamamlandı olarak güncellendi.

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 ile useCallback arasında veri aktarmak için useRef 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.

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.