React Geliştiricileri için Edebiyat

React Geliştiricileri için Edebiyat

Bu codelab hakkında

subjectSon güncelleme Haz 25, 2021
account_circleYazan: Elliott Marquez & Brian Vann

1. Giriş

Edebiyat nedir?

Lit, herhangi bir çerçevede çalışan veya hiçbir çerçeve olmadan çalışan hızlı ve hafif web bileşenleri oluşturmaya yönelik basit bir kitaplıktır. Lit'i kullanarak paylaşılabilir bileşenler, uygulamalar, tasarım sistemleri ve daha fazlasını oluşturabilirsiniz.

Neler öğreneceksiniz?

Çeşitli React kavramlarını Edebiyata dönüştürme, örneğin:

  • JSX ve Şablon oluşturma
  • Bileşenler ve Dekorlar
  • Eyalet & Yaşam döngüsü
  • Kancalar
  • Çocuklar
  • Referanslar
  • Arabuluculuk Durumu

Neler oluşturacaksınız?

Bu codelab'in sonunda React bileşeni kavramlarını Lit analoglarına dönüştürebileceksiniz.

Gerekenler

  • Chrome, Safari, Firefox veya Edge'in en son sürümü.
  • HTML, CSS, JavaScript ve Chrome Geliştirici Araçları hakkında bilgi sahibi olmak.
  • Tepki Bilgisi
  • (Gelişmiş) En iyi geliştirme deneyimi için VS Code'u indirin. Ayrıca VS Code ve NPM için lit-plugin'e ihtiyacınız vardır.

2. Edebiyat - Tepki

Lit'in temel kavramları ve yetenekleri React'in temel kavramlarına pek çok açıdan benzer ancak Lit'in bazı temel farklılıkları ve farkları da vardır:

Bu küçük

Özet çok küçük: React + ReactDOM'un 40+ kb'ye kıyasla küçültülmüş ve gzip'li boyutu yaklaşık 5 kb'dir.

Küçültülmüş ve KB cinsinden sıkıştırılmış paket boyutunun çubuk grafiği. Işık çubuğu 5 KB ve React + React DOM 42,2 KB'tır.

Hızlı

Lit'in şablon oluşturma sistemi olan lit-html'i React'in VDOM'siyle karşılaştıran herkese açık karşılaştırmalarda lit-html, en kötü durumda React'e kıyasla % 8-10 ve daha yaygın kullanım alanlarında %50+ daha hızlı sunulur.

LitElement (Lit'in bileşen temel sınıfı), lit-html'e minimum ek yük ekler ancak bellek kullanımı, etkileşim ve başlatma süreleri gibi bileşen özelliklerini karşılaştırırken React'in performansını%16-30 oranında artırır.

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.

İspanyolca modülleri ve Skypack veya UNPKG gibi modern CDN'ler sayesinde, başlamak için NPM'ye bile ihtiyacınız olmayabilir.

Yine de isterseniz lit kodunu oluşturmaya ve optimize etmeye devam edebilirsiniz. Yerel ES modülleri etrafında kısa süre önce yapılan geliştirici birleştirmesi Lit için iyi oldu. Lit yalnızca normal JavaScript'tir ve çerçeveye özel KSA'lara veya derleme işlemeye gerek yoktur.

Çerçeveden bağımsız

Lit'in bileşenleri, Web Bileşenleri adı verilen bir dizi web standardını temel alır. Bu durum, Lit'te bir bileşen oluşturmanın mevcut ve gelecekteki çerçevelerde işe yarayacağı anlamına gelir. HTML öğelerini destekliyorsa Web Bileşenleri'ni destekler.

Çerçeve birlikte çalışmayla ilgili tek sorun, çerçevelerin DOM için kısıtlayıcı desteğine sahip olmasıdır. React, bu çerçevelerden biridir ancak Refs ile kaçış yolu kullanılmasına olanak tanır. React in React iyi bir geliştirici deneyimi değildir.

Lit ekibi, @lit-labs/react adlı deneysel bir proje üzerinde çalışıyor. Bu proje, Lit bileşenlerinizi otomatik olarak ayrıştıracak ve referansları kullanmak zorunda kalmamanız için bir React sarmalayıcısı oluşturacak.

Ayrıca Custom Elements Her Yerde, hangi çerçeve ve kitaplıkların özel öğelerle düzgün çalıştığını gösterir.

Birinci sınıf TypeScript desteği

Tüm Lit kodunuzu JavaScript'te yazabilseniz de Lit, TypeScript'te yazılmıştır ve Lit ekibi, geliştiricilerin de TypeScript'i kullanmasını önerir.

Lit ekibi, lit-analyzer ve lit-plugin ile hem geliştirme hem de derleme zamanında TypeScript tür denetimi ve zekasını Lit şablonlarına getiren projelerin sürdürülmesine yardımcı olmak için Lit topluluğuyla çalışıyor.

Bir sayıya gösterilen boolenin ayarlanması için yanlış tür kontrolünü gösteren IDE'nin 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ıda yerleşiktir

Temel bileşenler yalnızca DOM'de bulunan HTML öğeleridir. Diğer bir deyişle, bileşenlerinizi incelemek için tarayıcınıza yönelik herhangi bir araç veya uzantı yüklemenize gerek yoktur.

Yalnızca geliştirme araçlarını açabilir, bir öğe seçebilir ve özelliklerini veya durumunu inceleyebilirsiniz.

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 codelab'in yazıldığı sırada Lit ekibi SSR araçlarını kararlı bir biçimde henüz kullanıma sunmamıştır. Ancak Lit ekibi halihazırda Google ürünleri genelinde sunucu tarafında oluşturulan bileşenleri dağıtmıştır ve React uygulamalarında SSR'yi test etmiştir. Lit ekibi bu araçları yakında GitHub'da harici olarak kullanıma sunmayı umuyor.

Bu sırada Edebiyat ekibinin kaydettiği ilerlemeyi buradan takip edebilirsiniz.

Katılımı azdır.

Edebiyat, kullanmak için büyük bir taahhüt gerektirmez. Lit'te bileşenler derleyebilir ve mevcut projenize ekleyebilirsiniz. Web bileşenleri başka çerçevelerde çalıştığından uygulamayı beğenmezseniz uygulamanın tamamını aynı anda dönüştürmeniz gerekmez.

Lit'te bir uygulama geliştirdiniz mi ve başka bir uygulamaya geçmek mi istiyorsunuz? O zaman mevcut Lit uygulamanızı yeni çerçevenizin içine yerleştirip dilediğiniz her şeyi yeni çerçevenin bileşenlerine taşıyabilirsiniz.

Ayrıca birçok modern çerçeve, web bileşenlerinde çıktıları destekler, yani genellikle Lit öğesinin içine sığabilirler.

3. Kurulum ve Playground&#39;u keşfediyor

Bu codelab'i iki şekilde yapabilirsiniz:

  • Tamamen çevrimiçi olarak, tarayıcınızdan yapabilirsiniz.
  • (Gelişmiş) Bu işlemi VS Code'u kullanarak yerel makinenizde yapabilirsiniz

Koda erişme

Codelab boyunca Edebiyat oyun alanına şu şekilde bağlantılar verilecektir:

Oyun alanı, tamamen tarayıcınızda çalışan bir kod korumalı alanıdır. TypeScript ve JavaScript dosyalarını derleyip çalıştırabilir, ayrıca düğüm modüllerine yapılan içe aktarmaları otomatik olarak çözümleyebilir. ör.

// before
import './my-file.js';
import 'lit';

// after
import './my-file.js';
import 'https://cdn.skypack.dev/lit';

Bu kontrol noktalarını başlangıç noktaları olarak kullanarak eğitici içeriğin tamamını Edebiyat oyun alanında uygulayabilirsiniz. VS Code kullanıyorsanız bu kontrol noktalarını herhangi bir adımın başlangıç kodunu indirmek için kullanabilir ve ayrıca bunları çalışmanızı kontrol etmek için de kullanabilirsiniz.

Işıklı oyun alanının kullanıcı arayüzünü keşfetmek

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 Gaming kullanıcı arayüzü ekran görüntüsünde, bu codelab'de kullanacağınız bölümler vurgulanmaktadı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 Kod kurulumu (Gelişmiş)

Bu VS Code kurulumunu kullanmanın avantajları şunlardır:

  • Şablon türü kontrolü
  • Şablon zekası ve otomatik tamamlama

NPM, VS Code (lit-plugin eklentisiyle) yüklüyse ve bu ortamı nasıl kullanacağınızı biliyorsanız, aşağıdakileri yaparak bu projeleri indirip başlatmanız yeterlidir:

  • İndir düğmesine basın
  • tar dosyasının içeriğini bir dizine çıkarın
  • (TS varsa) es modülleri ve es2015+ komutlarını döndüren hızlı bir tsconfig ayarlayın
  • Yalın modül tanımlayıcıları çözümleyebilen bir geliştirici sunucusu yükleyin (Lit ekibi @web/dev-server'ı önerir)
  • 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 Edebiyat'ta şablon oluşturmanın temellerini öğreneceksiniz.

JSX ve Lit şablonları

JSX, React kullanıcılarının JavaScript kodlarında kolayca şablon yazmalarına olanak tanıyan bir JavaScript söz dizimi uzantısıdır. Basit şablonlar da benzer bir amaca hizmet eder: Bileşenin kullanıcı arayüzünü, kendi durumunun işlevi olarak ifade etmek.

Temel Söz Dizimi

React'te şuna benzer bir JSX hello world oluşturursunuz:

import 'react';
import ReactDOM from 'react-dom';

const name = 'Josh Perez';
const element = (
 
<>
   
<h1>Hello, {name}</h1>
   
<div>How are you?</div>
 
</>
);

ReactDOM.render(
 
element,
 
mountNode
);

Yukarıdaki örnekte iki öğe ve bir "name" öğesi eklenmiştir değişkenine eklenmelidir. Edebiyat'ta şunları yaparsınız:

import {html, render} from 'lit';

const name = 'Josh Perez';
const element = html`
  <
h1>Hello, ${name}</h1>
  <
div>How are you?</div>`;

render(
 
element,
 
mountNode
);

Lit şablonlarının, şablonlarında birden fazla öğeyi gruplandırmak için Tepki Parçası'na ihtiyacı olmadığına dikkat edin.

Lit'te şablonlar html etiketli şablonla LITelal sarmalanır. Bu şablon da Lit'in adını taşır.

Şablon Değerleri

Lit şablonları, TemplateResult olarak bilinen diğer Lit şablonlarını kabul edebilir. Örneğin, name öğesini italik (<i>) etiketleri içine alın ve N.B etiketli bir düz şablon şablonuyla sarmalayın.Tek tırnak karakterini (') değil, vurgu işareti karakterini (`) kullandığınızdan emin olun.

import {html, render} from 'lit';

const name = html`<i>Josh Perez</i>`;
const element = html`
  <
h1>Hello, ${name}</h1>
  <
div>How are you?</div>`;

render(
 
element,
 
mountNode
);

Lit TemplateResult öğeleri dizi, dize ve diğer TemplateResult öğelerinin yanı sıra yönergeleri de kabul edebilir.

Alıştırma için aşağıdaki React kodunu Lit'e dönüştürmeyi deneyin:

const itemsToBuy = [
  <li>Bananas</li>,
  <li>oranges</li>,
  <li>apples</li>,
  <li>grapes</li>
];
const element = (
  <>
    <h1>Things to buy:</h1>
    <ol>
      {itemsToBuy}
    </ol>
  </>);

ReactDOM.render(
  element,
  mountNode
);

Yanıt:

import {html, render} from 'lit';

const itemsToBuy = [
 
html`<li>Bananas</li>`,
 
html`<li>oranges</li>`,
 
html`<li>apples</li>`,
 
html`<li>grapes</li>`
];
const element = html`
  <
h1>Things to buy:</h1>
  <
ol>
   
${itemsToBuy}
  <
/ol>`;

render(
 
element,
 
mountNode
);

Pas oluşturma ve döşeme sahneleri

JSX ile Lit'in söz dizimleri arasındaki en büyük farklardan biri, veri bağlama söz dizimidir. Örneğin, bağlamaları olan şu React girişini alın:

const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element =
  <input
      disabled={disabled}
      className={`static-class ${myClass}`}
      defaultValue={value}/>;

ReactDOM.render(
  element,
  mountNode
);

Yukarıdaki örnekte, aşağıdakileri yapan bir giriş tanımlanır:

  • Tanımlanmış bir değişkene devre dışı bırakılır (bu durumda yanlış)
  • Sınıfı static-class ve bir değişken (bu örnekte "static-class my-class") olarak ayarlar
  • Varsayılan değer ayarlar

Edebiyat'ta şunları yaparsınız:

import {html, render} from 'lit';

const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element = html`
  <
input
     
?disabled=${disabled}
     
class="static-class ${myClass}"
     
.value=${value}>`;

render(
 
element,
 
mountNode
);

Edebiyat örneğinde, disabled özelliğini açıp kapatmak için bir boole bağlaması eklenmiştir.

Ardından, className yerine doğrudan class özelliği ile bir bağlama bulunur. Sınıfları değiştirmek için bildirim temelli bir yardımcı olan classMap yönergesini kullanmıyorsanız class özelliğine birden fazla bağlama ekleyebilirsiniz.

Son olarak, value özelliği girişte ayarlanır. React'in aksine bu işlem, girişin yerel uygulamasını ve davranışını takip ettiğinden giriş öğesini salt okunur olarak ayarlamaz.

Lit prop bağlama söz dizimi

html`<my-element ?attribute-name=${booleanVar}>`;
  • ? öneki, bir öğedeki özelliği açıp kapatmak için kullanılan bağlama söz dizimidir
  • inputRef.toggleAttribute('attribute-name', booleanVar) etiketine eşdeğer
  • inputElement.hasAttribute('disabled') === true nedeniyle, disabled="false" olarak disabled kullanan öğeler DOM tarafından doğru olarak okunmaya devam eder.
html`<my-element .property-name=${anyVar}>`;
  • . öneki, bir öğenin özelliğini ayarlamak için kullanılan bağlama söz dizimidir
  • inputRef.propertyName = anyVar etiketine eşdeğer
  • Nesneler, diziler veya sınıflar gibi karmaşık verileri iletmek için idealdir
html`<my-element attribute-name=${stringVar}>`;
  • Bir öğenin özelliğine bağlanır
  • inputRef.setAttribute('attribute-name', stringVar) etiketine eşdeğer
  • Temel değerler, stil kuralı seçiciler ve querySelector için uygundur

Geçiş işleyiciler

const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element =
  <input
      onClick={() => console.log('click')}
      onChange={e => console.log(e.target.value)} />;

ReactDOM.render(
  element,
  mountNode
);

Yukarıdaki örnekte, aşağıdakileri yapan bir giriş tanımlanır:

  • "click" kelimesini günlüğe kaydet giriş tıklandığında
  • Kullanıcı bir karakter yazdığında giriş değerini günlüğe kaydet

Edebiyat'ta şunları yaparsınız:

import {html, render} from 'lit';

const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element = html`
  <
input
     
@click=${() => console.log('click')}
     
@input=${e => console.log(e.target.value)}>`;

render(
 
element,
 
mountNode
);

Edebiyat örneğinde, @click ile click etkinliğine eklenmiş bir işleyici vardır.

Ardından, yerel change etkinliği yalnızca blur tarihinde etkinleştiğinden (soyutları bu etkinlikler üzerinden tepki ver) onChange kullanmak yerine <input> etkinliğinin yerel input etkinliği için bir bağlantı bulunur.

Lit etkinlik işleyici söz dizimi

html`<my-element @event-name=${() => {...}}></my-element>`;
  • @ öneki, etkinlik işleyici için bağlama söz dizimidir
  • inputRef.addEventListener('event-name', ...) etiketine eşdeğer
  • Yerel DOM etkinlik adlarını kullanır

5. Bileşenler ve Dekorlar

Bu bölümde edebiyat sınıfı bileşenleri ve işlevleri hakkında bilgi edineceksiniz. Durum ve Kancalar sonraki bölümlerde daha ayrıntılı olarak ele alınacaktır.

Sınıf Bileşenleri ve LitElement

React sınıfı bileşeninin Lit eşdeğeri, LitElement ve Lit'in "reaktif özellikler" kavramıdır React'in özellikleri ve durumunun birleşimidir. Örneğin:

import React from 'react';
import ReactDOM from 'react-dom';

class Welcome extends React.Component {
 
constructor(props) {
   
super(props);
   
this.state = {name: ''};
 
}

 
render() {
   
return <h1>Hello, {this.props.name}</h1>;
 
}
}

const element = <Welcome name="Elliott"/>
ReactDOM.render(
 
element,
 
mountNode
);

Yukarıdaki örnekte şu özelliklere sahip bir React bileşeni vardır:

  • name oluşturur
  • Varsayılan name değerini boş dize ("") olarak ayarlar
  • name adlı kişiyi "Elliott" adlı kullanıcıya yeniden atar

LitElement'te bu işlemi şu şekilde yaparsınız:

TypeScript'te:

import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';

@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
 
@property({type: String})
 
name = '';

 
render() {
   
return html`<h1>Hello, ${this.name}</h1>`
 
}
}

JavaScript'te:

import {LitElement, html} from 'lit';

class WelcomeBanner extends LitElement {
 
static get properties() {
   
return {
     
name: {type: String}
   
}
 
}

 
constructor() {
   
super();
   
this.name = '';
 
}

 
render() {
   
return html`<h1>Hello, ${this.name}</h1>`
 
}
}

customElements.define('welcome-banner', WelcomeBanner);

Ayrıca HTML dosyasında:

<!-- index.html -->
<head>
  <script type="module" src="./index.js"></script>
</head>
<body>
  <welcome-banner name="Elliott"></welcome-banner>
</body>

Yukarıdaki örnekte neler olduğuna ilişkin bir inceleme:

@property({type: String})
name = '';
  • Bileşeninizin herkese açık API'sinin bir parçası olan herkese açık reaktif bir özelliği tanımlar
  • Bileşeninizde bir özelliğin (varsayılan olarak) yanı sıra bir özelliği sunar
  • Bileşenin özelliğinin (dize olan) bir değere nasıl çevrileceğini tanımlar
static get properties() {
  return {
    name: {type: String}
  }
}
  • Bu, @property TS tasarımcısıyla aynı işlevi görür ancak JavaScript'te yerel olarak çalışır
render() {
  return html`<h1>Hello, ${this.name}</h1>`
}
  • Bu, herhangi bir reaktif özellik değiştirildiğinde çağrılır
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
  ...
}
  • Bu, bir HTML Öğesi etiketi adını sınıf tanımıyla ilişkilendirir
  • Özel Öğeler standardı nedeniyle, etiket adı kısa çizgi (-) içermelidir olmalıdır
  • LitElement içindeki this, özel öğe örneğini ifade eder (bu örnekte <welcome-banner>)
customElements.define('welcome-banner', WelcomeBanner);
  • Bu, @customElement TS tasarımcısının JavaScript eşdeğeridir
<head>
  <script type="module" src="./index.js"></script>
</head>
  • Özel öğe tanımını içe aktarır
<body>
 
<welcome-banner name="Elliott"></welcome-banner>
</body>
  • Özel öğeyi sayfaya ekler
  • name özelliğini 'Elliott' olarak ayarlar

İşlev Bileşenleri

Edebiyatta JSX veya ön işlemci kullanılmadığı için bir işlev bileşeni 1:1 yoruma sahip değildir. Bununla birlikte, özellikleri alan ve DOM'yi bu özelliklere dayanarak oluşturan bir işlev oluşturmak oldukça basittir. Örneğin:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Elliott"/>
ReactDOM.render(
  element,
  mountNode
);

Özetle bu şu şekilde olacaktır:

import {html, render} from 'lit';

function Welcome(props) {
 
return html`<h1>Hello, ${props.name}</h1>`;
}

render(
 
Welcome({name: 'Elliott'}),
 
document.body.querySelector('#root')
);

6. Eyalet & Yaşam döngüsü

Bu bölümde Lit'in durumu ve yaşam döngüsü hakkında bilgi edineceksiniz.

Eyalet

Lit'in "Reaktif Özellikler" kavramı React'in durumu ve sahne unsurlarının bir karışımıdır. Reaktif Özellikler, değiştirildiğinde bileşenin yaşam döngüsünü tetikleyebilir. Reaktif özelliklerin iki varyantı vardır:

Herkese açık reaktif mülkler

// React
import React from 'react';

class MyEl extends React.Component {
 
constructor(props) {
   
super(props)
   
this.state = {name: 'there'}
 
}

 
componentWillReceiveProps(nextProps) {
   
if (this.props.name !== nextProps.name) {
     
this.setState({name: nextProps.name})
   
}
 
}
}

// Lit (TS)
import {LitElement} from 'lit';
import {property} from 'lit/decorators.js';

class MyEl extends LitElement {
 
@property() name = 'there';
}
  • Tanımlayan: @property
  • React'in özellikleri ve durumuna benzer ama değişebilir
  • Bileşenin tüketicileri tarafından erişilen ve ayarlanan herkese açık API

Dahili reaktif durum

// React
import React from 'react';

class MyEl extends React.Component {
 
constructor(props) {
   
super(props)
   
this.state = {name: 'there'}
 
}
}

// Lit (TS)
import {LitElement} from 'lit';
import {state} from 'lit/decorators.js';

class MyEl extends LitElement {
 
@state() name = 'there';
}
  • Tanımlayan: @state
  • React'in durumuna benzer ancak değişebilir
  • Genellikle bileşen veya alt sınıfların içinden erişilen dahili gizli durum

Yaşam döngüsü

Lit yaşam döngüsü React'in yaşam döngüsüne oldukça benzer ancak önemli bazı farklılıklar vardır.

constructor

// React (js)
import React from 'react';

class MyEl extends React.Component {
 
constructor(props) {
   
super(props);
   
this.state = { counter: 0 };
   
this._privateProp = 'private';
 
}
}

// Lit (ts)
class MyEl extends LitElement {
 
@property({type: Number}) counter = 0;
 
private _privateProp = 'private';
}

// Lit (js)
class MyEl extends LitElement {
 
static get properties() {
   
return { counter: {type: Number} }
 
}
 
constructor() {
   
this.counter = 0;
   
this._privateProp = 'private';
 
}
}
  • Litrenin eşdeğeri de constructor
  • Süper çağrıya herhangi bir bilgi iletmeye gerek yoktur.
  • Çağrı yapan (tamamen kapsayıcı değil):
    • document.createElement
    • document.innerHTML
    • new ComponentClass()
    • Sayfada yeni sürüme geçirilmemiş bir etiket adı varsa ve tanım yüklenip @customElement veya customElements.define ile kaydedilmişse
  • İşlev olarak React'in constructor işlevine benzer

render

// React
render() {
  return <div>Hello World</div>
}

// Lit
render() {
  return html`<div>Hello World</div>`;
}
  • Litrenin eşdeğeri de render
  • Oluşturulabilir herhangi bir sonucu döndürebilir, ör. TemplateResult veya string vb.
  • React'e benzer şekilde, render() yalın bir işlev olmalıdır
  • createRenderRoot() tarafından döndürülen düğümde oluşturulur (varsayılan olarak ShadowRoot)

componentDidMount

componentDidMount, Lit'in firstUpdated ve connectedCallback yaşam döngüsü geri çağırmalarının kombinasyonuna benzer.

firstUpdated

import Chart from 'chart.js';

// React
componentDidMount() {
 
this._chart = new Chart(this.chartElRef.current, {...});
}

// Lit
firstUpdated() {
 
this._chart = new Chart(this.chartEl, {...});
}
  • Bileşenin şablonu bileşenin kökünde ilk kez oluşturulduğunda çağrılır
  • Yalnızca öğe bağlıysa çağrılır (ör. bu düğüm DOM ağacına eklenene kadar document.createElement('my-component') aracılığıyla çağrılmaz
  • Burası, bileşen tarafından oluşturulan DOM'nin kullanılmasını gerektiren bileşen kurulumunu yapmak için iyi bir yerdir
  • React'in firstUpdated içindeki reaktif özelliklerde yapı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, DOM'den çıkarılan özel öğeler yok edilmez ve böylece "bağlanabilir" olabilir. birden çok kez
    • firstUpdated tekrar çağrılmayacak
  • DOM'yi yeniden başlatmak veya bağlantı kesildiğinde temizlenen etkinlik işleyicileri yeniden eklemek için kullanışlıdır
  • Not: connectedCallback, firstUpdated tarihinden önce çağrılabilir. Bu nedenle, ilk görüşmede DOM kullanılamayabilir.

componentDidUpdate

// React
componentDidUpdate(prevProps) {
  if (this.props.title !== prevProps.title) {
    this._chart.setTitle(this.props.title);
  }
}

// Lit (ts)
updated(prevProps: PropertyValues<this>) {
  if (prevProps.has('title')) {
    this._chart.setTitle(this.title);
  }
}
  • Edebiyat eşdeğeri updated ("update"in İngilizce son zamanı kullanılır)
  • React'in aksine updated, ilk oluşturma sırasında da çağrılır
  • İşlev olarak React'in componentDidUpdate işlevine benzer

componentWillUnmount

// React
componentWillUnmount() {
  this.window.removeEventListener('resize', this.boundOnResize);
}

// Lit
disconnectedCallback() {
  super.disconnectedCallback();
  this.window.removeEventListener('resize', this.boundOnResize);
}
  • Edebiyat eşdeğeri, disconnectedCallback ile benzer
  • React bileşenlerinin aksine, özel öğeler DOM'den çıkarıldığında bileşen kaldırılmaz
  • componentWillUnmount işlevinin 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 çöplerini toplayabilmesi için etkinlik işleyicileri ve sızdıran referansları temizlemek amacıyla kullanışlıdır

Antrenman

import React from 'react';
import ReactDOM from 'react-dom';

class Clock extends React.Component {
 
constructor(props) {
   
super(props);
   
this.state = {date: new Date()};
 
}

 
componentDidMount() {
   
this.timerID = setInterval(
     
() => this.tick(),
     
1000
   
);
 
}

 
componentWillUnmount() {
   
clearInterval(this.timerID);
 
}

 
tick() {
   
this.setState({
     
date: new Date()
   
});
 
}

 
render() {
   
return (
     
<div>
       
<h1>Hello, world!</h1>
       
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
     
</div>
   
);
 
}
}

ReactDOM.render(
  <
Clock />,
 
document.getElementById('root')
);

Yukarıdaki örnekte, aşağıdakileri yapan basit bir saat vardır:

  • "Hello World! Öyle" ve saatin kaç olduğunu
  • Her saniyede saat güncellenir
  • Ayrıldığında, işareti çağıran aralığı temizler

Öncelikle bileşen sınıf bildirimiyle başlayın:

// Lit (TS)
// some imports here are imported in advance
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';

@customElement('lit-clock')
class LitClock extends LitElement {
}

// Lit (JS)
// `html` is imported in advance
import {LitElement, html} from 'lit';

class LitClock extends LitElement {
}

customElements.define('lit-clock', LitClock);

Daha sonra, bileşenin kullanıcıları date öğesini doğrudan ayarlayamayacağı için date öğesini başlatın ve @state ile dahili reaktif özellik olarak bildirin.

// Lit (TS)
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';

@customElement('lit-clock')
class LitClock extends LitElement {
 
@state() // declares internal reactive prop
 
private date = new Date(); // initialization
}

// Lit (JS)
import {LitElement, html} from 'lit';

class LitClock extends LitElement {
 
static get properties() {
   
return {
     
// declares internal reactive prop
     
date: {state: true}
   
}
 
}

 
constructor() {
   
super();
   
// initialization
   
this.date = new Date();
 
}
}

customElements.define('lit-clock', LitClock);

Daha sonra, şablonu oluşturun.

// Lit (JS & TS)
render
() {
  return html`
    <div>
      <h1>Hello, World!</h1>
      <h2>It is ${this.date.toLocaleTimeString()}.</h2>
    </div>
  `;
}

Şimdi de tick yöntemini uygulayın.

tick() {
 
this.date = new Date();
}

Ardından, componentDidMount uygulanmasına geçilir. Tekrarlamak gerekirse, Lit analog'u firstUpdated ve connectedCallback'nın bir karışımıdır. Bu bileşende, setInterval ile tick çağrısı yapmak kök içindeki DOM'ye erişim gerektirmez. Ayrıca, öğe doküman ağacından kaldırıldığında aralık temizlenir. Dolayısıyla, öğe yeniden eklenirse aralığın yeniden başlaması gerekir. Bu nedenle connectedCallback burada daha iyi bir seçimdir.

// Lit (TS)
@customElement('lit-clock')
class LitClock extends LitElement {
  @state()
  private date = new Date();
  // initialize timerId for TS
  private timerId = -1 as unknown as ReturnType<typeof setTimeout>;

  connectedCallback() {
    super.connectedCallback();
    this.timerId = setInterval(
      () => this.tick(),
      1000
    );
  }

  ...
}

// Lit (JS)
constructor() {
  super();
  // initialization
  this.date = new Date();
  this.timerId = -1; // initialize timerId for JS
}

connectedCallback() {
  super.connectedCallback();
  this.timerId = setInterval(
    () => this.tick(),
    1000
  );
}

Son olarak, öğenin belge ağacından bağlantısı kesildikten sonra onay işaretinin yürütülmemesi için aralığı temizleyin.

// Lit (TS & JS)
disconnectedCallback() {
  super.disconnectedCallback();
  clearInterval(this.timerId);
}

Hepsini bir araya getirdiğimizde şu şekilde görünmelidir:

// Lit (TS)
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';

@customElement('lit-clock')
class LitClock extends LitElement {
 
@state()
 
private date = new Date();
 
private timerId = -1 as unknown as ReturnType<typeof setTimeout>;

 
connectedCallback() {
   
super.connectedCallback();
   
this.timerId = setInterval(
     
() => this.tick(),
     
1000
   
);
 
}

 
tick() {
   
this.date = new Date();
 
}

 
render() {
   
return html`
      <
div>
        <
h1>Hello, World!</h1>
        <
h2>It is ${this.date.toLocaleTimeString()}.</h2>
      <
/div>
   
`;
 
}

 
disconnectedCallback() {
   
super.disconnectedCallback();
   
clearInterval(this.timerId);
 
}
}

// Lit (JS)
import {LitElement, html} from 'lit';

class LitClock extends LitElement {
 
static get properties() {
   
return {
     
date: {state: true}
   
}
 
}

 
constructor() {
   
super();
   
this.date = new Date();
 
}

 
connectedCallback() {
   
super.connectedCallback();
   
this.timerId = setInterval(
     
() => this.tick(),
     
1000
   
);
 
}

 
tick() {
   
this.date = new Date();
 
}

 
render() {
   
return html`
      <
div>
        <
h1>Hello, World!</h1>
        <
h2>It is ${this.date.toLocaleTimeString()}.</h2>
      <
/div>
   
`;
 
}

 
disconnectedCallback() {
   
super.disconnectedCallback();
   
clearInterval(this.timerId);
 
}
}

customElements.define('lit-clock', LitClock);

7. Kancalar

Bu bölümde React Hook kavramlarını Edebiyat'a nasıl çevireceğinizi öğreneceksiniz.

React kancaları kavramları

Tepki kancaları, işlev bileşenlerinin "çengellenmesi" için bir yol sağlar içine alır. Bunun birkaç avantajı vardır.

  • Durum bilgili mantığın yeniden kullanımını basitleştirir
  • Bir bileşenin daha küçük işlevlere bölünmesine yardımcı olun

Ek olarak, işlev tabanlı bileşenlere odaklanma, React'in sınıfa dayalı söz dizimiyle ilgili şu gibi sorunları ele aldı:

  • props adlı kişinin constructor - super arasında geçmesi gerekiyor
  • constructor
      içindeki özelliklerin düzenli şekilde başlatılması
    • Bu, o zamanlar React ekibi tarafından belirtilmiş ancak ES2019 tarafından çözülen bir nedendi
  • this nedeniyle ortaya çıkan sorunlar artık bileşene atıfta bulunmuyor

Edebiyat'taki tepki kancası kavramları

Bileşenler ve Dekorlar bölümünde Lit, bir işlevden özel öğe oluşturmak için bir yöntem sunmaz, ancak LitElement, React sınıf bileşenleriyle ilgili temel sorunların çoğunu ele alır. Örneğin:

// React (at the time of making hooks)
import React from 'react';
import ReactDOM from 'react-dom';

class MyEl extends React.Component {
 
constructor(props) {
   
super(props); // Leaky implementation
   
this.state = {count: 0};
   
this._chart = null; // Deemed messy
 
}

 
render() {
   
return (
     
<>
       
<div>Num times clicked {count}</div>
       
<button onClick={this.clickCallback}>click me</button>
      <
/>
   
);
 
}

 
clickCallback() {
   
// Errors because `this` no longer refers to the component
   
this.setState({count: this.count + 1});
 
}
}

// Lit (ts)
class MyEl extends LitElement {
 
@property({type: Number}) count = 0; // No need for constructor to set state
 
private _chart = null; // Public class fields introduced to JS in 2019

 
render() {
   
return html`
        <
div>Num times clicked ${count}</div>
        <
button @click=${this.clickCallback}>click me</button>`;
 
}

 
private clickCallback() {
   
// No error because `this` refers to component
   
this.count++;
 
}
}

Lit bu sorunları nasıl ele alır?

  • constructor, bağımsız değişken kabul etmez
  • @event bağlamanın tümü this öğesine otomatik olarak bağlanıyor
  • Vakaların büyük çoğunluğunda this, özel öğenin referansıyla ilgilidir
  • Sınıf özellikleri artık sınıf üyeleri olarak örneklenebilir. Bu, kurucu tabanlı uygulamaları temizler

Reaktif Kumandalar

Hooks'un temel kavramları, Lit'te reaktif denetleyiciler olarak bulunur. Reaktif denetleyici kalıpları, durum bilgili mantığın paylaşılmasına, bileşenlerin daha küçük ve daha modüler bitlere bölünmesine ve bir öğenin güncelleme yaşam döngüsüne bağlanmasına olanak tanır.

Reaktif denetleyici, LitElement gibi bir denetleyici ana makinesinin güncelleme yaşam döngüsüne bağlanabilen bir nesne arayüzüdür.

ReactiveController ve reactiveControllerHost yaşam döngüsü şu şekildedir:

interface ReactiveController {
  hostConnected(): void;
  hostUpdate(): void;
  hostUpdated(): void;
  hostDisconnected(): void;
}
interface ReactiveControllerHost {
  addController(controller: ReactiveController): void;
  removeController(controller: ReactiveController): void;
  requestUpdate(): void;
  readonly updateComplete: Promise<boolean>;
}

Reaktif bir denetleyici oluşturup addController ile bir ana makineye ekleyerek denetleyicinin yaşam döngüsü, ana makinenin yaşam döngüsüyle birlikte çağrılır. Örneğin, Eyalet & Yaşam döngüsü bölümü:

import React from 'react';
import ReactDOM from 'react-dom';

class Clock extends React.Component {
 
constructor(props) {
   
super(props);
   
this.state = {date: new Date()};
 
}

 
componentDidMount() {
   
this.timerID = setInterval(
     
() => this.tick(),
     
1000
   
);
 
}

 
componentWillUnmount() {
   
clearInterval(this.timerID);
 
}

 
tick() {
   
this.setState({
     
date: new Date()
   
});
 
}

 
render() {
   
return (
     
<div>
       
<h1>Hello, world!</h1>
       
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
     
</div>
   
);
 
}
}

ReactDOM.render(
  <
Clock />,
 
document.getElementById('root')
);

Yukarıdaki örnekte, aşağıdakileri yapan basit bir saat vardır:

  • "Hello World! Öyle" ve saatin kaç olduğunu
  • Her saniyede saat güncellenir
  • Ayrıldığında, işareti çağıran aralığı temizler

Bileşen iskelesinin oluşturulması

Öncelikle bileşen sınıf bildirimiyle başlayın ve render işlevini ekleyin.

// Lit (TS) - index.ts
import {LitElement, html} from 'lit';
import {customElement} from 'lit/decorators.js';

@customElement('my-element')
class MyElement extends LitElement {
 
render() {
   
return html`
      <
div>
        <
h1>Hello, world!</h1>
        <
h2>It is ${'time to get Lit'}.</h2>
      <
/div>
   
`;
 
}
}

// Lit (JS) - index.js
import {LitElement, html} from 'lit';

class MyElement extends LitElement {
 
render() {
   
return html`
      <
div>
        <
h1>Hello, world!</h1>
        <
h2>It is ${'time to get Lit'}.</h2>
      <
/div>
   
`;
 
}
}

customElements.define('my-element', MyElement);

Denetleyiciyi oluşturma

Şimdi clock.ts ürününe geçin, ClockController için bir sınıf oluşturun ve constructor ayarını yapın:

// Lit (TS) - clock.ts
import {ReactiveController, ReactiveControllerHost} from 'lit';

export class ClockController implements ReactiveController {
 
private readonly host: ReactiveControllerHost;

 
constructor(host: ReactiveControllerHost) {
   
this.host = host;
   
host.addController(this);
 
}

 
hostConnected() {
 
}

 
private tick() {
 
}

 
hostDisconnected() {
 
}
}

// Lit (JS) - clock.js
export class ClockController {
 
constructor(host) {
   
this.host = host;
   
host.addController(this);
 
}

 
hostConnected() {
 
}

 
tick() {
 
}

 
hostDisconnected() {
 
}
}

ReactiveController arayüzünü paylaştığı sürece reaktif bir denetleyici herhangi bir şekilde oluşturulabilir. Ancak hem ReactiveControllerHost arayüzünde yer alabilecek constructor öğesine sahip bir sınıfın hem de denetleyiciyi başlatmak için gereken diğer tüm özelliklerin kullanılması, Lit ekibinin çoğu temel durumda kullanmayı tercih ettiği bir kalıptır.

Şimdi React yaşam döngüsü geri çağırmalarını denetleyici geri çağırmalarına çevirmeniz gerekiyor. Kısaca:

  • componentDidMount
    • LitElement'ın connectedCallback cihazına
    • Kumandanın hostConnected cihazına
  • ComponentWillUnmount
    • LitElement'ın disconnectedCallback cihazına
    • Kumandanın hostDisconnected cihazına

React yaşam döngüsünü Lit yaşam döngüsüne çevirme hakkında daha fazla bilgi için bkz. Durum ve Yaşam döngüsü bölümünü inceleyin.

Ardından, hostConnected geri çağırmasını ve tick yöntemlerini uygulayın ve hostDisconnected aralığındaki aralığı temizleyin. Boşlukları Durum ve Yaşam döngüsü bölümünü inceleyin.

// Lit (TS) - clock.ts
export class ClockController implements ReactiveController {
  private readonly host: ReactiveControllerHost;
  private interval = 0 as unknown as ReturnType<typeof setTimeout>;
  date = new Date();

  constructor(host: ReactiveControllerHost) {
    this.host = host;
    host.addController(this);
  }

  hostConnected() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  private tick() {
    this.date = new Date();
  }

  hostDisconnected() {
    clearInterval(this.interval);
  }
}

// Lit (JS) - clock.js
export class ClockController {
  interval = 0;
  host;
  date = new Date();

  constructor(host) {
    this.host = host;
    host.addController(this);
  }

  hostConnected() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  tick() {
    this.date = new Date();
  }

  hostDisconnected() {
    clearInterval(this.interval);
  }
}

Denetleyiciyi kullanma

Saat denetleyicisini kullanmak için kumandayı içe aktarın ve bileşeni index.ts veya index.js ürününde güncelleyin.

// Lit (TS) - index.ts
import {LitElement, html, ReactiveController, ReactiveControllerHost} from 'lit';
import {customElement} from 'lit/decorators.js';
import {ClockController} from './clock.js';

@customElement('my-element')
class MyElement extends LitElement {
 
private readonly clock = new ClockController(this); // Instantiate

 
render() {
   
// Use controller
   
return html`
      <
div>
        <
h1>Hello, world!</h1>
        <
h2>It is ${this.clock.date.toLocaleTimeString()}.</h2>
      <
/div>
   
`;
 
}
}

// Lit (JS) - index.js
import {LitElement, html} from 'lit';
import {ClockController} from './clock.js';

class MyElement extends LitElement {
 
clock = new ClockController(this); // Instantiate

 
render() {
   
// Use controller
   
return html`
      <
div>
        <
h1>Hello, world!</h1>
        <
h2>It is ${this.clock.date.toLocaleTimeString()}.</h2>
      <
/div>
   
`;
 
}
}

customElements.define('my-element', MyElement);

Denetleyiciyi kullanmak için denetleyici ana makinesine (<my-element> bileşenidir) bir referans ileterek denetleyiciyi örneklendirmeniz ve ardından denetleyiciyi render yönteminde kullanmanız gerekir.

Denetleyicide yeniden oluşturmayı tetikleme

Saatin gösterildiğinden, ancak saatin güncellenmediğini unutmayın. Bunun nedeni denetleyicinin her saniyede bir tarih ayarlamasına rağmen ana makinenin güncelleme yapmamasıdır. Bunun nedeni, date öğesinin artık ClockController sınıfında değişmesi, bileşenin bundan sonra değişmemesidir. Bu nedenle, date, denetleyicide ayarlandıktan sonra ana makineye güncelleme yaşam döngüsünü host.requestUpdate() ile çalıştırması söylenmelidir.

// Lit (TS & JS) - clock.ts / clock.js
private tick() {
  this.date = new Date();
  this.host.requestUpdate();
}

Zaman azalıyor!

Kancaların kullanıldığı yaygın kullanım alanlarının daha ayrıntılı bir karşılaştırması için lütfen Gelişmiş Konular - Kancalar bölümüne bakın.

8. Çocuklar

Bu bölümde Edebiyat'ta alt öğeleri yönetmek için slotları nasıl kullanacağınızı öğreneceksiniz.

Yuvalar ve Çocuklar

Slotlar, bileşenleri iç içe yerleştirmenize olanak tanıyarak bestelemenize olanak tanır.

React'te çocuklar eşyalardan kalıtılır. Varsayılan alan props.children, render işlevi ise varsayılan alanın konumlandırıldığı yeri tanımlar. Örneğin:

const MyArticle = (props) => {
 return <article>{props.children}</article>;
};

props.children öğelerinin HTML öğeleri değil, React Bileşenleri olduğunu unutmayın.

Edebiyat'ta alt öğeler, oluşturma işlevinde slot öğeleriyle oluşturulur. Alt öğelerin React ile aynı şekilde devralınmadığına dikkat edin. Lit'te alt öğeler, alanlara eklenmiş HTMLElement'lardır. Bu eke Projeksiyon adı verilir.

@customElement("my-article")
export class MyArticle extends LitElement {
  render() {
    return html`
      <article>
        <slot></slot>
      </article>
   `;
  }
}

Birden Çok Yuva

React'te birden fazla slot eklemek, temelde daha fazla öğe devralmayla aynıdır.

const MyArticle = (props) => {
  return (
    <article>
      <header>
        {props.headerChildren}
      </header>
      <section>
        {props.sectionChildren}
      </section>
    </article>
  );
};

Benzer şekilde, daha fazla <slot> öğesi eklendiğinde Edebiyat'ta daha fazla alan oluşturulur. Birden fazla alan, name özelliğiyle tanımlanır: <slot name="slot-name">. Bu, çocukların hangi alana atanacaklarını bildirmelerine olanak tanır.

@customElement("my-article")
export class MyArticle extends LitElement {
  render() {
    return html`
      <article>
        <header>
          <slot name="headerChildren"></slot>
        </header>
        <section>
          <slot name="sectionChildren"></slot>
        </section>
      </article>
   `;
  }
}

Varsayılan Alan İçeriği

Slotlar, bu alana yansıtılan düğüm olmadığında alt ağaçlarını gösterir. Düğümler bir yuvaya yansıtıldığında, bu alan alt ağacını göstermez ve bunun yerine yansıtılan düğümleri gösterir.

@customElement("my-element")
export class MyElement extends LitElement {
  render() {
    return html`
      <section>
        <div>
          <slot name="slotWithDefault">
            <p>
             This message will not be rendered when children are attached to this slot!
            <p>
          </slot>
        </div>
      </section>
   `;
  }
}

Alanlara alt öğe atama

React'te alt öğeler, bir bileşenin özellikleri aracılığıyla alanlara atanır. Aşağıdaki örnekte React öğeleri, headerChildren ve sectionChildren özelliklerine iletilir.

const MyNewsArticle = () => {
 return (
   <MyArticle
     headerChildren={<h3>Extry, Extry! Read all about it!</h3>}
     sectionChildren={<p>Children are props in React!</p>}
   />
 );
};

Edebiyat'ta, alt alanlara slot özelliği kullanılarak atanır.

@customElement("my-news-article")
export class MyNewsArticle extends LitElement {
  render() {
    return html`
      <my-article>
        <h3 slot="headerChildren">
          Extry, Extry! Read all about it!
        </h3>
        <p slot="sectionChildren">
          Children are composed with slots in Lit!
        </p>
      </my-article>
   `;
  }
}

Varsayılan alan (ör. <slot>) yoksa ve özel öğenin alt öğelerinin slot özelliğiyle (ör. <div slot="foo">) eşleşen name özelliğine sahip bir alan (ör. <slot name="foo">) yoksa bu düğüm yansıtılmaz ve gösterilmez.

9. Ref

Zaman zaman geliştiricinin HTMLElement API'sine erişmesi gerekebilir.

Bu bölümde Edebiyat'ta öğe referanslarını nasıl edineceğinizi öğreneceksiniz.

React referansları

React bileşeni, çağrıldığında sanal DOM oluşturan bir dizi işlev çağrısına aktarılır. Bu sanal DOM, ReactDOM tarafından yorumlanır ve HTMLElements oluşturur.

React'te Ref'ler, oluşturulmuş bir HTMLElement'ı içerecek şekilde bellekteki alandır.

const RefsExample = (props) => {
 const inputRef = React.useRef(null);
 const onButtonClick = React.useCallback(() => {
   inputRef.current?.focus();
 }, [inputRef]);

 return (
   <div>
     <input type={"text"} ref={inputRef} />
     <br />
     <button onClick={onButtonClick}>
       Click to focus on the input above!
     </button>
   </div>
 );
};

Yukarıdaki örnekte Tepki bileşeni aşağıdaki işlemleri yapar:

  • Boş bir metin girişi ve metin içeren bir düğme oluştur
  • Düğme tıklandığında girişe odaklanır

İlk oluşturma işleminden sonra React, ref özelliği aracılığıyla oluşturulan HTMLInputElement değerine inputRef.current değerini ayarlar.

Lit "Referanslar" @query ile birlikte

Lit, tarayıcıya yakın bir yerde bulunur ve yerel tarayıcı özellikleri üzerinde çok ince bir soyutlama oluşturur.

Edebiyat'taki refs ifadesine karşılık gelen Tepki, @query ve @queryAll tasarımcıları tarafından döndürülen HTMLElement öğesidir.

@customElement("my-element")
export class MyElement extends LitElement {
  @query('input') // Define the query
  inputEl!: HTMLInputElement; // Declare the prop

  // Declare the click event listener
  onButtonClick() {
    // Use the query to focus
    this.inputEl.focus();
  }

  render() {
    return html`
      <input type="text">
      <br />
      <!-- Bind the click listener -->
      <button @click=${this.onButtonClick}>
        Click to focus on the input above!
      </button>
   `;
  }
}

Yukarıdaki örnekte, Lit bileşeni şunları yapar:

  • @query tasarımcısını kullanarak MyElement üzerinde bir özellik tanımlar (HTMLInputElement için alıcı oluşturuluyor).
  • onButtonClick adlı bir tıklama etkinliği geri çağırması bildirir ve ekler.
  • Düğme tıklandığında girişe odaklanır

JavaScript'te, @query ve @queryAll tasarımcıları sırasıyla querySelector ve querySelectorAll işlemlerini gerçekleştirir. Bu, @query('input') inputEl!: HTMLInputElement; işlevinin JavaScript eşdeğeridir

get inputEl() {
 
return this.renderRoot.querySelector('input');
}

Lit bileşeni, render yönteminin şablonunu my-element köküne kaydettikten sonra, @query tasarımcısı artık inputEl ürününün, oluşturma kökünde bulunan ilk input öğesini döndürmesine izin verir. @query belirtilen öğeyi bulamazsa null değerini döndürür.

Oluşturma kökünde birden fazla input öğesi varsa @queryAll bir düğüm listesi döndürür.

10. Arabuluculuk Durumu

Bu bölümde, Edebiyat'ta bileşenler arasında durum uyumlulaştırmasından nasıl yararlanacağınızı öğreneceksiniz.

Yeniden Kullanılabilir Bileşenler

React, yukarıdan aşağıya veri akışı olan işlevsel oluşturma ardışık düzenlerini taklit eder. Ebeveynler, eşyalar aracılığıyla çocuklara durum bilgisi verirler. Çocuklar, öğelerdeki geri aramaları kullanarak ebeveynleriyle iletişim kurar.

const CounterButton = (props) => {
  const label = props.step < 0
    ? `- ${-1 * props.step}`
    : `+ ${props.step}`;


  return (
    <button
      onClick={() =>
        props.addToCounter(props.step)}>{label}</button>
  );
};

Yukarıdaki örnekte, bir React bileşeni şunları yapar:

  • props.step değerine göre bir etiket oluşturur.
  • Etiketi +adım veya -adım olan bir düğme oluşturur
  • Tıklamada bağımsız değişken olarak props.step ile props.addToCounter çağrısı yaparak üst bileşeni günceller

Edebiyat'ta geri çağırmaları aktarmak mümkün olsa da geleneksel kalıplar farklıdır. Yukarıdaki örnekteki React Bileşeni, aşağıdaki örnekte Edebiyat Bileşeni olarak yazılabilir:

@customElement('counter-button')
export class CounterButton extends LitElement {
  @property({type: Number}) step: number = 0;

  onClick() {
    const event = new CustomEvent('update-counter', {
      bubbles: true,
      detail: {
        step: this.step,
      }
    });

    this.dispatchEvent(event);
  }

  render() {
    const label = this.step < 0
      ? `- ${-1 * this.step}`  // "- 1"
      : `+ ${this.step}`;      // "+ 1"

    return html`
      <button @click=${this.onClick}>${label}</button>
    `;
  }
}

Yukarıdaki örnekte, Lit Bileşeni şunları yapacak:

  • step reaktif özelliğini oluştur
  • Tıklandığında öğenin step değerini taşıyan update-counter adlı bir özel etkinlik gönderin

Tarayıcı etkinlikleri, alt öğelerden üst öğelere çıkar. Etkinlikler, çocukların etkileşim etkinliklerini ve durum değişikliklerini yayınlamasına olanak tanır. Tepki, temel olarak ters yönde bir durum geçer. Bu nedenle, React Bileşenlerinin dağıtıldığını görmek ve etkinlikleri, Lit Bileşenleriyle aynı şekilde dinlemek alışılmadık bir durumdur.

Durum Bilgili Bileşenler

React'te durumu yönetmek için kancalar yaygın olarak kullanılır. CounterButton Bileşeni yeniden kullanılarak bir MyCounter Bileşeni oluşturulabilir. addToCounter öğesinin her iki CounterButton örneğine nasıl iletildiğine dikkat edin.

const MyCounter = (props) => {
 const [counterSum, setCounterSum] = React.useState(0);
 const addToCounter = useCallback(
   (step) => {
     setCounterSum(counterSum + step);
   },
   [counterSum, setCounterSum]
 );

 return (
   <div>
     <h3>&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 uygulamasını step tarihine kadar güncellemek için addToCounter kullanır.

Benzer bir MyCounter uygulaması Edebiyat'ta da gerçekleştirilebilir. addToCounter öğesinin counter-button öğesine nasıl aktarılmadığına dikkat edin. Bunun yerine, geri çağırma bir üst öğedeki @update-counter etkinliğine etkinlik işleyici olarak bağlanır.

@customElement("my-counter")
export class MyCounter extends LitElement {
  @property({type: Number}) count = 0;

  addToCounter(e: CustomEvent<{step: number}>) {
    // Get step from detail of event or via @query
    this.count += e.detail.step;
  }

  render() {
    return html`
      <div @update-counter="${this.addToCounter}">
        <h3>&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
  • count adlı etkinliği, update-counter etkinliğinin detail.step. kısmındaki değeri ekleyerek günceller
  • counter-button öğesinin step değerini, step özelliği aracılığıyla ayarlar

Ebeveynlerden çocuklara yapılan değişiklikleri yayınlamak için Lit'te reaktif özelliklerin kullanılması daha geleneksel bir yaklaşımdır. Aynı şekilde, ayrıntıları aşağıdan yukarı doğru baloncuk oluşturmak için tarayıcının etkinlik sistemini kullanmak iyi bir uygulamadır.

Bu yaklaşım, en iyi uygulamaları izler ve Lit'in web bileşenleri için platformlar arası destek sağlama hedefine uygundur.

11. Stil

Bu bölümde Edebiyat'ta stil hakkında bilgi edineceksiniz.

Stil

Edebiyat, öğeleri biçimlendirmek için çeşitli yöntemler ve yerleşik bir çözüm sunuyor.

Satır İçi Stiller

Edebiyat, satır içi stilleri ve bunlara bağlamayı destekler.

import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';

@customElement('my-element')
class MyElement extends LitElement {
 
render() {
   
return html`
      <
div>
        <
h1 style="color:orange;">This text is orange</h1>
        <
h1 style="color:rebeccapurple;">This text is rebeccapurple</h1>
      <
/div>
   
`;
 
}
}

Yukarıdaki örnekte her biri satır içi stile sahip 2 başlık vardır.

Şimdi bir kenarlığı içe aktarıp border-color.js ile turuncu metne bağlayın:

...
import borderColor from './border-color.js';

...

html`
 
...
  <
h1 style="color:orange;${borderColor}">This text is orange</h1>
 
...`

Stil dizesini her seferinde hesaplamak biraz sinir bozucu olabilir. Bu nedenle Lit bu konuda yardımcı olacak bir yönerge sunuyor.

styleMap

styleMap yönergesi, satır içi stilleri ayarlamak için JavaScript'in kullanılmasını kolaylaştırır. Örneğin:

import {LitElement, html, css} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {styleMap} from 'lit/directives/style-map.js';

@customElement('my-element')
class MyElement extends LitElement {
 
@property({type: String})
 
color = '#000'

 
render() {
   
// Define the styleMap
   
const headerStyle = styleMap({
     
'border-color': this.color,
   
});

   
return html`
      <
div>
        <
h1
         
style="border-style:solid;
          <
!-- Use the styleMap -->
         
border-width:2px;${headerStyle}">
         
This div has a border color of ${this.color}
        <
/h1>
        <
input
         
type="color"
         
@input=${e => (this.color = e.target.value)}
         
value="#000">
      <
/div>
   
`;
 
}
}

Yukarıdaki örnek şunları sağlar:

  • Kenarlık ve renk seçici içeren bir h1 görüntüler
  • border-color değerini, renk seçicideki değerle değiştirir

Buna ek olarak, h1 stilini ayarlamak için kullanılan styleMap bulunur. styleMap, React'in style özellik bağlama söz dizimine benzer bir söz dizimi uygular.

CSSResult

Bileşenlerin stilini belirlemek için önerilen yol, css etiketli düz şablon kullanmaktır.

import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';

const ORANGE = css`orange`;

@customElement('my-element')
class MyElement extends LitElement {
 
static styles = [
   
css`
     
#orange {
       
color: ${ORANGE};
     
}

     
#purple {
       
color: rebeccapurple;
     
}
   
`
 
];

 
render() {
   
return html`
      <
div>
        <
h1 id="orange">This text is orange</h1>
        <
h1 id="purple">This text is rebeccapurple</h1>
      <
/div>
   
`;
 
}
}

Yukarıdaki örnek şunları sağlar:

  • Bağlama sahip bir CSS etiketli şablon sabit değerini tanımlar
  • Kimlik içeren iki h1 öğesinin renklerini ayarlar

css şablon etiketini kullanmanın avantajları:

  • Sınıf başına ve örnek başına bir kez ayrıştırılır
  • Modülün yeniden kullanılabilirliği göz önünde bulundurularak uygulandı
  • Stilleri kolayca kendi dosyalarına ayırabilir
  • CSS Özel Özellikler çoklu dolgusu ile uyumlu

Ayrıca index.html içindeki <style> etiketine dikkat edin:

<!-- index.html -->
<style>
  h1 {
    color: red !important;
  }
</style>

Proje, bileşenlerinizin kapsamını belirler köklerine kadar uzanıyor. Bu, stillerin içeri girip çıkmayacağı anlamına gelir. Edebiyat ekibi, stilleri bileşenlere aktarmak için Edebiyat stili kapsamının kapsamlı bir şekilde ele geçirilebildiği CSS Özel Mülklerinin kullanılmasını önerir.

Stil Etiketleri

<style> etiketlerini şablonlarınızda satır içi olarak kullanmak da mümkündür. Tarayıcı, bu stil etiketlerini tekilleştirir, ancak bunları şablonlarınıza yerleştirildiğinde, css etiketli şablonda olduğu gibi sınıf başına değil, bileşen örneği başına ayrıştırılır. Ayrıca, CSSResult öğelerinin tarayıcı tekilleştirilmesi çok daha hızlıdır.

Stiller için şablonunuzda <link rel="stylesheet"> kullanmak da mümkündür. Ancak, stillenmemiş içeriğin (FOUC) başlangıçta yanıp sönmesine neden olabileceği için bu da önerilmez.

12. İleri Düzey Konular (isteğe bağlı)

JSX ve Şablon oluşturma

Edebi ve Sanal DOM

Lit-html, her bir düğümü farklı kılan geleneksel bir Sanal DOM içermez. Bunun yerine, ES2015'in etiketli şablon değişmez değeri spesifikasyonuna uygun performans özelliklerini kullanır. Etiketli şablon değişmez değerleri, etiket işlevleri ekli olan düz şablon dizeleridir.

Değişmez şablon örneği aşağıda verilmiştir:

const str = 'string';
console.log(`This is a template literal ${str}`);

Etiketli bir düz şablon örneğini aşağıda görebilirsiniz:

const tag = (strings, ...values) => ({strings, values});
const f = (x) => tag`hello ${x} how are you`;
console.log(f('world')); // {strings: ["hello ", " how are you"], values: ["world"]}
console.log(f('world').strings === f(1 + 2).strings); // true

Yukarıdaki örnekte etiket tag işlevidir ve f işlevi, etiketli bir değişmez şablon çağrısını döndürür.

Edebiyat'taki performans sihrinin büyük bir kısmı, etiket işlevine iletilen dize dizilerinin aynı işaretçiye sahip olmasından kaynaklanır (ikinci console.log içinde gösterildiği gibi). Tarayıcı, aynı değişmez şablon değerini (ör. AST'de aynı konumda) kullandığından, her etiket işlevi çağrısında yeni bir strings dizisi yeniden oluşturmaz. Böylece Lit'in bağlama, ayrıştırma ve şablon önbelleğine alma işlemleri, çok fazla çalışma zamanı farkı ek yükü olmadan bu özelliklerden yararlanabilir.

Etiketlenmiş şablon değişmez değerlerinin bu yerleşik tarayıcı davranışı, Lit'e önemli bir performans avantajı sağlar. Geleneksel Sanal DOM'lerin çoğu, çalışmalarının büyük kısmını JavaScript'te gerçekleştirir. Bununla birlikte, etiketlenmiş şablon değişmez değerleri, farklılıklarının çoğunu tarayıcının C++'ta gerçekleştirir.

React veya Preact ile HTML etiketli şablon değişmez değerlerini kullanmak istiyorsanız Edebiyat ekibi htm kitaplığını önerir.

Google Codelabs sitesinde ve bazı online kod düzenleyicilerinde olduğu gibi, etiketli şablonda düz yazım söz dizimi vurgulama özelliğinin çok yaygın olmadığını fark edeceksiniz. Atom ve GitHub'ın kod bloğu vurgulayıcısı gibi bazı IDE'ler ve metin düzenleyiciler varsayılan olarak bunları destekler. Edebiyat ekibi ayrıca, Edebiyat projelerinize söz dizimi vurgulama, yazım kontrolü ve bilgi toplama özellikleri ekleyen bir VS Code eklentisi olan lit-plugin gibi projeleri sürdürmek için toplulukla çok yakın bir şekilde çalışır.

Edebi ve JSX + Tepki DOM'u

JSX tarayıcıda çalışmaz ve bunun yerine JSX'i JavaScript işlev çağrılarına (genellikle Babel üzerinden) dönüştürmek için bir ön işlemci kullanır.

Örneğin, Babel bunu dönüştürür:

const element = <div className="title">Hello World!</div>;
ReactDOM.render(element, mountNode);

şunu yaz:

const element = React.createElement('div', {className: 'title'}, 'Hello World!');
ReactDOM.render(element, mountNode);

Ardından React DOM, React çıkışını alıp gerçek DOM'ye dönüştürür (özellikler, özellikler, etkinlik işleyiciler vb.).

Lit-html, tarayıcıda aktarma veya ön işlemci olmadan çalışabilen etiketli şablon değişmez değerlerini kullanır. Diğer bir deyişle, Lit'i kullanmaya başlamak için yalnızca bir HTML dosyası, bir ES modülü komut dosyası ve bir sunucu yeterlidir. Tamamen tarayıcı tarafından çalıştırılabilen bir komut dosyası aşağıda verilmiştir:

<!DOCTYPE html>
<html>
 
<head>
   
<script type="module">
     
import {html, render} from 'https://cdn.skypack.dev/lit';

     
render(
       
html`<div>Hello World!</div>`,
       
document.querySelector('.root')
     
)
   
</script>
 
</head>
 
<body>
   
<div class="root"></div>
 
</body>
</html>

Ayrıca, Lit'in şablon oluşturma sistemi olan lit-html, geleneksel bir Sanal DOM'u değil, doğrudan DOM API'yi kullandığından Lit 2'nin boyutu React (2, 8 kb) + 40 kb'lık küçültülmüş ve gizip uygulanmış e-tabloya kıyasla 5 kb'ın altında küçültülmüş ve gzip uygulanmıştır.

Etkinlikler

React, sentetik etkinlik sistemi kullanır. Bu, tepki-dom'un her bileşende kullanılacak her etkinliği tanımlaması ve her düğüm türü için bir camelCase etkinlik işleyici eşdeğeri sağlaması gerektiği anlamına gelir. Sonuç olarak, JSX'in özel etkinlik için etkinlik işleyici tanımlayan bir yöntemi yoktur ve geliştiricilerin ref kullanmaları ve zorunlu olarak bir işleyici uygulaması gerekir. Bu durum, React'i dikkate almayan kitaplıkları entegre ederken vahşetin altında bir geliştirici deneyimi oluşturur ve bu nedenle React'e özel sarmalayıcı yazmak zorunda kalır.

Lit-html, DOM'ye doğrudan erişir ve yerel etkinlikleri kullanır. Dolayısıyla etkinlik işleyicileri eklemek @event-name=${eventNameListener} kadar kolaydır. Bu, etkinlik işleyici ekleme ve etkinlik tetikleme işlemleri için daha az çalışma zamanı ayrıştırma işleminin yapıldığı anlamına gelir.

Bileşenler ve Dekorlar

Tepki bileşenleri ve özel öğeler

Gelişmiş seçeneklerde LitElement, bileşenlerini paketlemek için özel öğeler kullanır. Özel öğeler, bileşenlere ayırma söz konusu olduğunda React bileşenleri arasında bazı ödünler verir (durum ve yaşam döngüsü, Durum ve Yaşam Döngüsü bölümünde daha ayrıntılı bir şekilde açıklanmıştır).

Özel Öğelerin bileşen sistemi olarak sunduğu bazı avantajlar şunlardır:

  • Tarayıcı için yereldir ve herhangi bir araç gerektirmez
  • innerHTML ile document.createElement ile querySelector arasındaki her tarayıcı API'sine uyar
  • Genellikle çerçeveler arasında kullanılabilir
  • customElements.define ve "hydrate" ile gecikmeli olarak kaydedilebilir DOM

Özel Öğelerin React bileşenlerine kıyasla bazı dezavantajları vardır:

  • Sınıf tanımlamadan özel öğe oluşturulamaz (dolayısıyla JSX benzeri işlevsel bileşenler oluşturulamaz)
  • Bir kapanış etiketi içermelidir
    • Not: Geliştiriciye kolaylık sağlayan tarayıcı satıcıları, kendi kendine kapanan etiket spesifikasyonuna pişman olma eğilimindedir. Bu nedenle, yeni özelliklerde kendiliğinden kapanan etiketler kullanılmama eğilimindedir.
  • DOM ağacına, düzen sorunlarına neden olabilecek fazladan bir düğüm ekler
  • JavaScript aracılığıyla kayıtlı olmalıdır

Özel öğeler tarayıcıda yerleşik olarak bulunduğu için Lit, özelleştirilmiş öğe sistemi yerine özel öğelerle kullanmaya başladı. Lit ekibi, çerçeveler arası avantajların bileşen soyutlama katmanının sağladığı avantajlardan ağır bastığını düşünüyor. Aslına bakılırsa, Lit ekibinin lit-ssr alanındaki çalışmaları, JavaScript kaydıyla ilgili temel sorunların üstesinden gelmeyi başardı. Buna ek olarak, GitHub gibi bazı şirketler, isteğe bağlı dokunuşlarla sayfaları kademeli olarak iyileştirmek için özel öğe geç kaydından yararlanır.

Özel öğelere veri iletme

Özel öğelerle ilgili yaygın bir yanlış kanı, verilerin yalnızca dize olarak aktarılabileceğidir. Bu yanılgı, muhtemelen öğe özelliklerinin yalnızca dize olarak yazılabileceği gerçeğinden kaynaklanmaktadır. Lit, dize özelliklerini tanımlı türlerine atayacağı doğru olsa da, özel öğeler karmaşık verileri özellik olarak kabul edebilir.

Örneğin, aşağıdaki LitElement tanımını ele alalım:

// data-test.ts
import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';

@customElement('data-test')
class DataTest extends LitElement {
 
@property({type: Number})
 
num = 0;

 
@property({attribute: false})
 
data = {a: 0, b: null, c: [html`<div>hello</div>`, html`<div>world</div>`]}

 
render() {
   
return html`
      <
div>num + 1 = ${this.num + 1}</div>
      <
div>data.a = ${this.data.a}</div>
      <
div>data.b = ${this.data.b}</div>
      <
div>data.c = ${this.data.c}</div>`;
 
}
}

Bir özelliğin dize değerini number değerine dönüştürecek bir temel reaktif özellik num tanımlanır ve ardından attribute:false ile karmaşık veri yapısı oluşturulur. Bu da Lit'in özellik işlemeyi devre dışı bırakır.

Bu özel öğeye nasıl veri iletileceği aşağıda açıklanmıştır:

<head>
 
<script type="module">
   
import './data-test.js'; // loads element definition
   
import {html} from './data-test.js';

   
const el = document.querySelector('data-test');
   
el.data = {
     
a: 5,
     
b: null,
     
c: [html`<div>foo</div>`,html`<div>bar</div>`]
   
};
 
</script>
</head>
<body>
 
<data-test num="5"></data-test>
</body>

Eyalet & Yaşam döngüsü

Diğer Tepki Yaşam Döngüsü Geri Çağırmaları

static getDerivedStateFromProps

Edebiyatta donanım ve durum aynı sınıf özellikleri olduğundan edebiyatta eşdeğeri yoktur

shouldComponentUpdate

  • Edebiyat eşdeğeri: shouldUpdate
  • React'in aksine ilk oluşturmada çağrılır
  • İşlev olarak React'in shouldComponentUpdate işlevine benzer

getSnapshotBeforeUpdate

Litrede getSnapshotBeforeUpdate, hem update hem de willUpdate ile benzerdir

willUpdate

  • update tarihinden önce arandı
  • getSnapshotBeforeUpdate işlevinin 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 benzer bir yaşam döngüsü geri çağırması olmadığından önceki bölümde bahsedilmeyen çeşitli yaşam döngüsü geri çağırmaları vardır. Bunlar:

attributeChangedCallback

Öğenin observedAttributes değerlerinden biri değiştiğinde çağrılır. Hem observedAttributes hem de attributeChangedCallback, özel öğeler spesifikasyonunun bir parçasıdır ve Lit öğeleri için özellik API'si sağlamak üzere arka planda Lit tarafından uygulanır.

adoptedCallback

Bileşen yeni bir dokümana taşındığında (ör. HTMLTemplateElement cihazının documentFragment cihazından ana document cihazına. Bu geri çağırma, özel öğeler spesifikasyonunun da bir parçasıdır ve yalnızca bileşenin dokümanları değiştirdiği gelişmiş kullanım alanları için kullanılmalıdır.

Diğer yaşam döngüsü yöntemleri ve özellikleri

Bu yöntemler ve özellikler, yaşam döngüsü sürecini değiştirmek için çağırabileceğiniz, geçersiz kılabileceğiniz veya bekleyebileceğiniz sınıf üyeleridir.

updateComplete

Bu, güncelleme ve oluşturma yaşam döngüleri eşzamansız olduğundan öğenin güncellenmesi tamamlandığında çözümlenen bir Promise değeridir. Örnek:

async nextButtonClicked() {
 
this.step++;
 
// Wait for the next "step" state to render
  await
this.updateComplete;
 
this.dispatchEvent(new Event('step-rendered'));
}

getUpdateComplete

Bu yöntem, updateComplete çözümlendiğinde özelleştirilmesi için geçersiz kılınması gereken bir yöntemdir. Bu durum, bir bileşen bir alt bileşen oluşturduğunda ve bunların oluşturma döngülerinin senkronize olması gerektiğinde yaygın olarak görülür. ör.

class MyElement extends LitElement {
  ...
  async getUpdateComplete() {
    await super.getUpdateComplete();
    await this.myChild.updateComplete;
  }
}

performUpdate

Bu yöntem, güncelleme yaşam döngüsü geri çağırma yöntemidir. Güncellemenin eşzamanlı olarak yapılması gereken nadir durumlar veya özel planlamalar dışında genellikle buna gerek yoktur.

hasUpdated

Bileşen en az bir kez güncellendiyse bu özellik true olur.

isConnected

Özel öğeler spesifikasyonunun bir parçası. Öğe şu anda ana belge ağacına eklenmişse bu özellik true olacaktır.

Edebiyat Güncellemesi Yaşam Döngüsü Görselleştirmesi

Güncelleme yaşam döngüsü 3 bölümden oluşur:

  • Güncelleme öncesi
  • Güncelle
  • Güncelleme sonrası

Ön Güncelleme

Geri çağırma adlarına sahip düğümlerin yönlendirilmiş bir döngüsel grafiği. kurucusu requestUpdate&#39;i içerir. @property adlı başka bir anahtarı Mülk Belirleyici&#39;ye gönderir. AttributionChangedCallback&#39;i Mülk Ayarlayıcı olarak değiştirin. Özellik Ayarlayıcı&#39;yı hasChanged olarak ayarlayın. haschange, requestUpdate olarak değişti. requestUpdate ise bir sonraki güncelleme yaşam döngüsü grafiğini işaret eder.

requestUpdate sonrasında planlanmış bir güncelleme bekleniyor.

Güncelle

Geri çağırma adlarına sahip düğümlerin yönlendirilmiş bir döngüsel grafiği. PerformanceUpdate için güncelleme öncesi yaşam döngüsü noktalarının önceki resmindeki ok. receiveUpdate&#39;i değiştirin. shouldUpdate Points hem &quot;complete update if false&quot; (yanlışsa güncellemeyi tamamla) hem de willUpdate. olacak. oluşturma ve bir sonraki güncelleme sonrası yaşam döngüsü grafiğine geçin. oluşturma, bir sonraki güncelleme sonrası yaşam döngüsü grafiğini de işaret eder.

Güncelleme Sonrası

Geri çağırma adlarına sahip düğümlerin yönlendirilmiş bir döngüsel grafiği. Güncelleme yaşam döngüsü noktalarının önceki resmindeki ilk Güncelle&#39;nin yanındaki ok. önce güncellendi için güncellendi. güncelleme Tamamlandı olarak güncellendi.

Kancalar

Neden kancalar?

Gerekli durumun basit işlev bileşeni kullanım alanları için React'e kancalar eklendi. Birçok basit durumda, kancalı işlev bileşenleri, sınıf bileşeni eşdeğerlerinden çok daha basit ve okunabilir olma eğilimi gösterir. Yine de eşzamansız durum güncellemeleri sunmanın yanı sıra verileri kancalar veya efektler arasında aktarma konusunda, kanca modeli yeterli değildir ve reaktif denetleyiciler gibi sınıf tabanlı bir çözüm ortaya çıkma eğilimindedir.

API isteği kancaları ve kumandalar

API'den veri isteyen bir kanca yazmak yaygın bir uygulamadır. Örneğin, aşağıdakileri yapan bu React işlevi bileşenini alın:

  • index.tsx
    • Metin oluşturur
    • useAPI adlı kullanıcının yanıtını oluşturur
      • Kullanıcı Kimliği + Kullanıcı adı
      • Hata Mesajı
        • Kullanıcı 11'e ulaştığında 404 (tasarımdan)
        • API getirme işlemi iptal edilirse iptal hatası
      • Yükleniyor Mesajı
    • Bir işlem düğmesi oluşturur
      • Sonraki kullanıcı: Sonraki kullanıcı için API'yi getirir
      • İptal: Bu işlem API getirme işlemini iptal eder ve bir hata gösterir.
  • useApi.tsx
    • useApi özel kancası tanımlar
    • Eş zamansız olarak bir API'den kullanıcı nesnesi getirir mi?
    • Emisyon:
      • Kullanıcı adı
      • Getirme işleminin yüklenip yüklenmediği
      • Tüm hata mesajları
      • Getirme işlemini iptal etmek için geri çağırma
    • Kaldırılmışsa devam eden getirme işlemlerini iptal eder

Edebiyat + Reaktif Denetleyici uygulaması burada açıklanmaktadır.

Çıkarımlar:

  • Reaktif Denetleyiciler, özel kancalara benzer.
  • Geri çağırma işlevleri ve efektler arasında oluşturulamayan verileri iletme
    • React, useEffect ile useCallback arasında veri aktarmak için useRef kullanır
    • Edebiyat, özel sınıf mülkü kullanıyor
    • Tepki, temelde özel sınıf bir mülkün davranışını taklit eder

Ayrıca, kancalı React işlevi bileşeni söz dizimini ancak Lit'in derlemesiz ortamını gerçekten seviyorsanız Lit ekibi Haunted kitaplığını kesinlikle önerir.

Çocuklar

Varsayılan Aralık

HTML öğelerine bir slot özelliği verilmediğinde, varsayılan adsız alana atanırlar. Aşağıdaki örnekte MyApp, adlandırılmış bir alana bir paragrafı yerleştirecektir. Diğer paragraf varsayılan olarak adsız alana ayarlanır".

@customElement("my-element")
export class MyElement extends LitElement {
  render() {
    return html`
      <section>
        <div>
          <slot></slot>
        </div>
        <div>
          <slot name="custom-slot"></slot>
        </div>
      </section>
   `;
  }
}

@customElement("my-app")
export class MyApp extends LitElement {
  render() {
    return html`
      <my-element>
        <p slot="custom-slot">
          This paragraph will be placed in the custom-slot!
        </p>
        <p>
          This paragraph will be placed in the unnamed default slot!
        </p>
      </my-element>
   `;
  }
}

Zaman Aralığı Güncellemeleri

Alan alt öğelerinin yapısı değiştiğinde bir slotchange etkinliği tetiklenir. Lit bileşeni, etkinlik işleyiciyi bir slotchange etkinliğine bağlayabilir. Aşağıdaki örnekte, shadowRoot içindeki ilk alanın assignedNodes slotchange tarihinde konsola kaydedilir.

@customElement("my-element")
export class MyElement extends LitElement {
  onSlotChange(e: Event) {
    const slot = this.shadowRoot.querySelector('slot');
    console.log(slot.assignedNodes({flatten: true}));
  }

  render() {
    return html`
      <section>
        <div>
          <slot @slotchange="{this.onSlotChange}"></slot>
        </div>
      </section>
   `;
  }
}

Referanslar

Referans oluşturma

Hem Lit hem de React, render işlevleri çağrıldıktan sonra HTMLElement'a başvuru sunar. Ancak daha sonra Lit @query tasarımcısı veya React Referansı aracılığıyla döndürülen DOM'yi React ve Lit'in nasıl oluşturduğunu incelemek faydalı olabilir.

React, HTMLElements değil React Bileşenleri oluşturan işlevsel bir ardışık düzendir. Ref, HTMLElement oluşturulmadan önce tanımlandığı için bellekte bir alan ayrılır. Bu nedenle, gerçek DOM öğesi henüz oluşturulmadığından (veya oluşturulmadığından) (yani useRef(null)) Ref'in ilk değeri olarak null gösterilir.

ReactDOM, bir React Bileşenini HTMLElement'a dönüştürdükten sonra ReactComponent'ta ref adlı bir özellik arar. ReactDOM, mevcutsa HTMLElement'ın referansını ref.current öğesine yerleştirir.

LitElement, arka planda bir Şablon Öğesi oluşturmak için lit-html'deki html şablon etiketi işlevini kullanır. LitElement, şablonun içeriğini, oluşturulduktan sonra özel öğenin gölge DOM'sine damgalar. Gölge DOM, bir gölge kökü ile kapsüllenmiş kapsamlı bir DOM ağacıdır. Daha sonra @query tasarımcısı, mülk için kapsamlı kökte temel olarak bir this.shadowRoot.querySelector gerçekleştiren bir alıcı oluşturur.

Birden Çok Öğe Sorgula

Aşağıdaki örnekte @queryAll tasarımcısı, gölge kökündeki iki paragrafı bir NodeList olarak döndürür.

@customElement("my-element")
export class MyElement extends LitElement {
  @queryAll('p')
  paragraphs!: NodeList;

  render() {
    return html`
      <p>Hello, world!</p>
      <p>How are you?</p>
   `;
  }
}

Temel olarak @queryAll, paragraphs için this.shadowRoot.querySelectorAll() sonuçlarını döndüren bir alıcı oluşturur. JavaScript'te, bir alıcı aynı amacı yerine getirmesi gerektiği belirtilebilir:

get paragraphs() {
 
return this.renderRoot.querySelectorAll('p');
}

Sorgu Değiştiren Öğeler

@queryAsync tasarımcısı, başka bir öğe özelliğinin durumuna göre değişebilen düğümleri işlemek için daha uygundur.

Aşağıdaki örnekte @queryAsync ilk paragraf öğesini bulur. Ancak, paragraf öğesi yalnızca renderParagraph rastgele bir tek sayı oluşturduğunda oluşturulur. @queryAsync yönergesi, ilk paragraf kullanıma sunulduğunda çözümlenecek bir taahhüt döndürür.

@customElement("my-dissappearing-paragraph")
export class MyDisapppearingParagraph extends LitElement {
  @queryAsync('p')
  paragraph!: Promise<HTMLElement>;

  renderParagraph() {
    const randomNumber = Math.floor(Math.random() * 10)
    if (randomNumber % 2 === 0) {
      return "";
    }

    return html`<p>This checkbox is checked!`
  }

  render() {
    return html`
      ${this.renderParagraph()}
   `;
  }
}

Arabuluculuk Durumu

React'te kural, durum React'in kendisi tarafından aracılığı olduğundan, geri çağırma yöntemidir. Tepki olarak, öğelerin sağladığı duruma güvenmemek en iyisidir. DOM, oluşturma işleminin bir etkisidir.

Harici Durum

Lit ile birlikte Redux, MobX veya başka bir eyalet yönetimi kitaplığını kullanabilirsiniz.

Lit bileşenleri, tarayıcı kapsamında oluşturulur. Dolayısıyla, tarayıcı kapsamında da bulunan tüm kitaplıklar Lit'te kullanılabilir. Lit'teki mevcut durum yönetim sistemlerinden yararlanmak için çok sayıda muhteşem kitaplık oluşturuldu.

Vaadin'in Edebiyat bileşeninde Redux'tan nasıl yararlanılacağını açıklayan bir seri.

Büyük ölçekli bir sitenin MobX in Lit'ten nasıl yararlanabileceğini görmek için Adobe'nin lit-mobx paketine göz atın.

Ayrıca, geliştiricilerin GraphQL'yi web bileşenlerine nasıl dahil ettiklerini görmek için Apollo Elements'a da göz atın.

Lit, yerel tarayıcı özellikleriyle çalışır ve tarayıcı kapsamındaki durum yönetimi çözümlerinin çoğu Lit bileşeninde kullanılabilir.

Stil

Gölge DOM

Lit, bir Özel Öğe içinde stilleri ve DOM'yi yerel olarak kapsüllemek için Gölge DOM'u kullanır. Gölge Kökleri, ana belge ağacından ayrı bir gölge ağacı oluşturur. Bu, çoğu stilin bu doküman kapsamında yer aldığı anlamına gelir. Renk ve yazı tipiyle ilgili diğer stiller gibi belirli stiller sızdırılır.

Gölge DOM, CSS spesifikasyonuna yeni kavramlar ve seçiciler de ekliyor:

:host, :host(:hover), :host([hover]) {
  /* Styles the element in which the shadow root is attached to */
}

slot[name="title"]::slotted(*), slot::slotted(:hover), slot::slotted([hover]) {
  /*
   * Styles the elements projected into a slot element. NOTE: the spec only allows
   * styling the direcly slotted elements. Children of those elements are not stylable.
   */
}

Stilleri paylaşma

Lit, css şablon etiketleri aracılığıyla bileşenler arasında CSSTemplateResults biçimindeki stillerin paylaşılmasını kolaylaştırır. Örneğin:

// typography.ts
export const body1 = css`
 
.body1 {
   
...
 
}
`;

// my-el.ts
import {body1} from './typography.ts';

@customElement('my-el')
class MyEl Extends {
 
static get styles = [
   
body1,
   
css`/* local styles come after so they will override bod1 */`
 
]

 
render() {
   
return html`<div class="body1">...</div>`
 
}
}

Tema oluşturma

Gölge kökleri, genellikle yukarıdan aşağıya stil etiket yaklaşımları olan geleneksel tema oluşturma için biraz zorluk teşkil eder. Gölge DOM kullanan Web Bileşenleriyle tema oluşturma işlemi yapmak için geleneksel yöntem, CSS Özel Özellikleri aracılığıyla bir stil API'si sunmaktır. Örneğin, şu Materyal Tasarım'ın kullandığı bir kalıptır:

.mdc-textfield-outline {
  border-color: var(--mdc-theme-primary, /* default value */ #...);
}
.mdc-textfield--input {
  caret-color: var(--mdc-theme-primary, #...);
}

Bu işlemin ardından kullanıcı, özel özellik değerleri uygulayarak sitenin temasını değiştirir:

html {
  --mdc-theme-primary: #F00;
}
html[dark] {
  --mdc-theme-primary: #F88;
}

Yukarıdan aşağıya tema oluşturmak zorundaysanız ve stilleri gösteremiyorsanız her zaman createRenderRoot değerini geçersiz kılarak Gölge DOM'u devre dışı bırakarak this sonucunu döndürebilirsiniz. Bu durumda bileşenleriniz oluşturulur. şablonunu, özel öğeye ekli bir gölge kökü yerine özel öğenin kendisine ekler. Bu durumda şunları kaybedersiniz: stil kapsülleme, DOM kapsülleme ve alanlar.

Üretim

İrlanda 11

IE 11 gibi daha eski tarayıcıları desteklemeniz gerekiyorsa, yaklaşık 33 KB'lık bir boyuta gelen bazı çoklu dolguları yüklemeniz gerekecektir. Daha fazla bilgiye buradan ulaşabilirsiniz.

Koşullu Paketler

Lit ekibi, biri IE 11, diğeri modern tarayıcılar için olmak üzere iki farklı paket sunmanızı öneriyor. Bunun bazı avantajları vardır:

  • ES 6, daha hızlı sunulur ve müşterilerinizin çoğuna hizmet verir
  • Aktarılan ES 5, paket boyutunu önemli ölçüde artırıyor
  • Koşullu paketler iki olanaktan en iyi şekilde yararlanmanızı sağlar.
    • IE 11 desteği
    • Modern tarayıcılarda yavaşlama yok

Koşullu olarak sunulan paket oluşturma hakkında daha fazla bilgiyi buradaki belge sitemizde bulabilirsiniz.