लिट फ़ॉर रिएक्ट डेवलपर्स

1. परिचय

Lit क्या है

Lit एक आसान लाइब्रेरी है. इसका इस्तेमाल करके, तेज़ और हल्के वेब कॉम्पोनेंट बनाए जा सकते हैं. ये कॉम्पोनेंट किसी भी फ़्रेमवर्क में या बिना किसी फ़्रेमवर्क के काम करते हैं. Lit की मदद से, शेयर किए जा सकने वाले कॉम्पोनेंट, ऐप्लिकेशन, डिज़ाइन सिस्टम वगैरह बनाए जा सकते हैं.

आपको क्या सीखने को मिलेगा

React के कई कॉन्सेप्ट को Lit में ट्रांसलेट करने का तरीका. जैसे:

  • JSX और टेंप्लेट
  • कॉम्पोनेंट और प्रॉप
  • राज्य और लाइफ़साइकल
  • Hooks
  • बच्चे
  • रेफ़रंस
  • मध्यस्थता स्थिति

आपको क्या बनाना होगा

इस कोडलैब के आखिर में, React कॉम्पोनेंट के सिद्धांतों को Lit ऐनालॉग में बदला जा सकेगा.

आपको किन चीज़ों की ज़रूरत होगी

  • Chrome, Safari, Firefox या Edge का नया वर्शन.
  • एचटीएमएल, सीएसएस, JavaScript, और Chrome DevTools के बारे में जानकारी.
  • React के बारे में जानकारी
  • (बेहतर) अगर आपको डेवलपमेंट का बेहतरीन अनुभव चाहिए, तो VS Code डाउनलोड करें. आपको VS Code और NPM के लिए, lit-plugin की भी ज़रूरत होगी.

2. Lit बनाम React

Lit के मुख्य सिद्धांत और क्षमताएं, कई मायनों में React की तरह हैं. हालांकि, लिटरेचर में कुछ अहम अंतर और कुछ बातें भी हैं:

यह छोटा है

Lit छोटा है: React + ReactDOM के 40 से ज़्यादा केबी की तुलना में, इसमें करीब 5kb छोटा और gzip किया गया है.

बंडल के साइज़ का बार चार्ट, जिसे छोटा और केबी में कंप्रेस किया गया है. Lit बार का साइज़ 5 केबी और React + React DOM का साइज़ 42.2 केबी है

यह तेज़ है

सार्वजनिक बेंचमार्क में, Lit के टेंप्लेट सिस्टम, lit-html की तुलना React के VDOM से की जाती है. सबसे खराब मामले में, React की तुलना में lit-html का इस्तेमाल 8-10% ज़्यादा और इस्तेमाल के सामान्य मामलों में 50%से ज़्यादा तेज़ी के साथ होता है.

LitElement (Lit की कॉम्पोनेंट बेस क्लास), lit-html में ज़्यादा ओवरहेड नहीं जोड़ता. हालांकि, मेमोरी के इस्तेमाल, इंटरैक्शन, और स्टार्टअप के समय जैसी कॉम्पोनेंट सुविधाओं की तुलना करने पर, React की परफ़ॉर्मेंस को 16 से 30% तक बेहतर बनाता है.

परफ़ॉर्मेंस का ग्रुप वाला बार चार्ट, जिसमें लाइट की मिलीसेकंड में प्रतिक्रिया देने से तुलना की गई है (कम बेहतर है)

बिल्ड की ज़रूरत नहीं है

ब्राउज़र की नई सुविधाओं, जैसे कि ES मॉड्यूल और टैग किए गए टेंप्लेट लिटरल की मदद से, Lit को रन करने के लिए कंपाइल करने की ज़रूरत नहीं होती. इसका मतलब है कि डेवलपर एनवायरमेंट को किसी स्क्रिप्ट टैग + ब्राउज़र + सर्वर के साथ सेट अप किया जा सकता है. साथ ही, इसे सेट अप किया जा सकता है और इस्तेमाल किया जा सकता है.

ES मॉड्यूल और नए ज़माने के सीडीएन, जैसे कि Skypack या UNPKG के साथ, हो सकता है कि शुरुआत करने के लिए आपको NPM की ज़रूरत न पड़े!

हालांकि, अगर आप चाहें, तो अब भी लिट कोड बनाया और ऑप्टिमाइज़ किया जा सकता है. नेटिव ES मॉड्यूल के बारे में हाल ही में डेवलपर, एक साथ मिलकर काम करते हैं. यह Lit के लिए अच्छा है – lit, सिर्फ़ एक सामान्य JavaScript है और इसके लिए किसी खास फ़्रेमवर्क के लिए सीएलआई या बिल्ड हैंडलिंग की ज़रूरत नहीं है.

फ़्रेमवर्क एग्नोस्टिक

लिट के कॉम्पोनेंट वेब कॉम्पोनेंट नाम के वेब स्टैंडर्ड का एक सेट बनाते हैं. इसका मतलब है कि Lit में एक कॉम्पोनेंट बनाने पर, मौजूदा और आने वाले समय के फ़्रेमवर्क पर काम किया जा सकेगा. अगर यह एचटीएमएल एलिमेंट के साथ काम करता है, तो यह वेब कॉम्पोनेंट के साथ काम करता है.

फ़्रेमवर्क इंटरऑपरेबिलिटी से जुड़ी समस्याएं सिर्फ़ तब आती हैं, जब फ़्रेमवर्क में DOM के लिए पाबंदी वाली सहायता होती है. React इनमें से एक फ़्रेमवर्क है. हालांकि, यह रेफ़रंस के ज़रिए, एस्केप हैच की अनुमति देता है. React में रेफ़रंस, डेवलपर के लिए अच्छा अनुभव नहीं है.

Lit की टीम, @lit-labs/react नाम के एक एक्सपेरिमेंट पर काम कर रही है. यह प्रोजेक्ट, Lit के कॉम्पोनेंट अपने-आप पार्स करेगा और रिऐक्ट रैपर जनरेट करेगा. ऐसा इसलिए, ताकि आपको रेफ़रंस का इस्तेमाल न करना पड़े.

इसके अलावा, कस्टम एलिमेंट हर जगह से आपको यह पता चलेगा कि कौनसे फ़्रेमवर्क और लाइब्रेरी, कस्टम एलिमेंट के साथ अच्छी तरह से काम करती हैं!

प्रथम-स्तरीय TypeScript समर्थन

हालांकि, आपके सभी Lit कोड को JavaScript में लिखना मुमकिन है, लेकिन Lit को TypeScript में लिखा गया है और Lit टीम का सुझाव है कि डेवलपर भी TypeScript का इस्तेमाल करें!

Lit टीम, Lit कम्यूनिटी के साथ मिलकर उन प्रोजेक्ट को मैनेज करने में मदद कर रही है जो lit-analyzer और lit-plugin की मदद से, डेवलपमेंट और बिल्ड के समय, Lit टेंप्लेट में TypeScript टाइप की जांच और इंटेलिसेंस की सुविधा देते हैं.

किसी नंबर के लिए आउटलाइन किए गए बूलियन को सेट करने के लिए, गलत टाइप की जांच दिखाने वाले IDE का स्क्रीनशॉट

इंटेलिसेंस के सुझाव दिखाने वाले आईडीई का स्क्रीनशॉट

डेवलपर टूल, ब्राउज़र में पहले से मौजूद होते हैं

लिट कॉम्पोनेंट, डीओएम में सिर्फ़ एचटीएमएल एलिमेंट होते हैं. इसका मतलब है कि अपने कॉम्पोनेंट की जांच करने के लिए, आपको अपने ब्राउज़र के लिए कोई भी टूल या एक्सटेंशन इंस्टॉल करने की ज़रूरत नहीं है.

इसके लिए, आपको बस डेवलपर टूल खोलने होंगे, कोई एलिमेंट चुनना होगा, और उसकी प्रॉपर्टी या स्थिति को एक्सप्लोर करना होगा.

Chrome डेवलपर टूल की इमेज, जिसमें दिखाया गया है कि $0, <mwc-textfield> दिखाता है, $0.value, hello world दिखाता है, $0.outlined, true दिखाता है, और {$0}, प्रॉपर्टी एक्सपैंशन दिखाता है

इसे सर्वर साइड रेंडरिंग (एसएसआर) को ध्यान में रखकर बनाया गया है

Lit 2 को एसएसआर (सर्वर साइड रेंडरिंग) के साथ काम करने के लिए बनाया गया है. कोडलैब के इस मॉड्यूल को लिखते समय, Lit टीम ने अभी SSR टूल को स्थिर रूप में रिलीज़ नहीं किया है, लेकिन Lit टीम पहले से ही Google के सभी प्रॉडक्ट में सर्वर साइड से रेंडर किए गए कॉम्पोनेंट को डिप्लॉय कर रही है और उन्होंने React ऐप्लिकेशन में एसएसआर की जांच कर ली है. Lit की टीम को उम्मीद है कि वह जल्द ही इन टूल को GitHub पर रिलीज़ कर देगी.

इस दौरान, Lit टीम की प्रोग्रेस के बारे में यहां अपडेट पाएं.

इसमें कम खरीदारी होती है

Lit को इस्तेमाल करने के लिए, ज़्यादा दिलचस्पी की ज़रूरत नहीं है! Lit में कॉम्पोनेंट बनाए जा सकते हैं और उन्हें अपने मौजूदा प्रोजेक्ट में जोड़ा जा सकता है. अगर आपको ये फ़ॉर्मैट पसंद नहीं आते, तो आपको पूरे ऐप्लिकेशन को एक साथ बदलने की ज़रूरत नहीं है, क्योंकि वेब कॉम्पोनेंट दूसरे फ़्रेमवर्क में काम करते हैं!

क्या आपने Lit में पूरा ऐप्लिकेशन बनाया है और आपको उसमें कुछ और बदलना है? ठीक है, इसके बाद अपने मौजूदा Lit ऐप्लिकेशन को नए फ़्रेमवर्क के अंदर रखा जा सकता है. साथ ही, नए फ़्रेमवर्क के कॉम्पोनेंट में अपनी पसंद के मुताबिक डेटा माइग्रेट किया जा सकता है.

इसके अलावा, कई आधुनिक फ़्रेमवर्क, वेब कॉम्पोनेंट में आउटपुट के साथ काम करते हैं. इसका मतलब है कि वे आम तौर पर Lit एलिमेंट में फ़िट हो सकते हैं.

3. सेट अप करना और Playground को एक्सप्लोर करना

कोडलैब के इस मॉड्यूल को करने के दो तरीके हैं:

  • आप इसे ब्राउज़र में पूरी तरह से ऑनलाइन कर सकते हैं
  • (बेहतर) VS Code का इस्तेमाल करके, अपनी लोकल मशीन पर ऐसा किया जा सकता है

कोड ऐक्सेस करना

कोडलैब में, Lit के प्लेग्राउंड के लिंक इस तरह दिखेंगे:

प्लेग्राउंड एक कोड सैंडबॉक्स है, जो आपके ब्राउज़र में पूरी तरह से चलता है. यह TypeScript और JavaScript फ़ाइलों को कंपाइल और चला सकता है. साथ ही, यह नोड मॉड्यूल में इंपोर्ट को अपने-आप रिज़ॉल्व भी कर सकता है. उदाहरण के लिए,

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

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

इन चेकपॉइंट को शुरुआती पॉइंट के तौर पर इस्तेमाल करके, Lit प्लैटफ़ॉर्म पर पूरा ट्यूटोरियल किया जा सकता है. अगर VS Code का इस्तेमाल किया जा रहा है, तो किसी भी चरण के लिए शुरुआती कोड डाउनलोड करने के लिए, इन चेकपॉइंट का इस्तेमाल किया जा सकता है. साथ ही, इनका इस्तेमाल करके अपने काम की जांच की जा सकती है.

रोशनी से जगमगाते प्लेग्राउंड यूआई को एक्सप्लोर करें

फ़ाइल चुनने वाले टैब बार को सेक्शन 1 के तौर पर लेबल किया गया है, सेक्शन 2 के तौर पर कोड एडिटिंग सेक्शन, सेक्शन 3 के तौर पर आउटपुट की झलक, और &#39;झलक फिर से लोड करें बटन&#39; को सेक्शन 4 के तौर पर लेबल किया गया है

Lit Playground के यूज़र इंटरफ़ेस (यूआई) के स्क्रीनशॉट में, उन सेक्शन को हाइलाइट किया गया है जिनका इस्तेमाल इस कोडलैब में किया जाएगा.

  1. फ़ाइल चुनने वाला टूल. प्लस बटन पर ध्यान दें...
  2. फ़ाइल एडिटर.
  3. कोड की झलक.
  4. 'फिर से लोड करें' बटन.
  5. 'डाउनलोड करें' बटन.

VS Code सेटअप करना (बेहतर)

बनाम इस बनाम कोड सेटअप का इस्तेमाल करने के फ़ायदे यहां दिए गए हैं:

  • टेंप्लेट टाइप की जांच करना
  • टेंप्लेट इंटेलिजेंस और अपने-आप पूरा होने की सुविधा

अगर आपके पास पहले से ही NPM, VS Code (lit-plugin प्लग इन के साथ) इंस्टॉल है और आपको उस एनवायरमेंट का इस्तेमाल करने का तरीका पता है, तो इन प्रोजेक्ट को डाउनलोड करके चलाने के लिए, यह तरीका अपनाएं:

  • 'डाउनलोड करें' बटन दबाएं
  • टार फ़ाइल के कॉन्टेंट को डायरेक्ट्री में निकालें
  • (अगर TS) क्विक tsconfig सेट अप करें, जो es मॉड्यूल और es2015+ को आउटपुट करता है
  • ऐसा डेवलपर सर्वर इंस्टॉल करें जो बेर मॉड्यूल स्पेसिफ़ायर को हल कर सके. Lit टीम का सुझाव है कि @web/dev-server का इस्तेमाल करें
  • डेव सर्वर चलाएं और अपना ब्राउज़र खोलें (अगर @web/dev-server का इस्तेमाल किया जा रहा है, तो npx web-dev-server --node-resolve --watch --open का इस्तेमाल किया जा सकता है)
    • अगर उदाहरण के तौर पर package.json का इस्तेमाल किया जा रहा है, तो npm run dev का इस्तेमाल करें

4. JSX और टेंप्लेटिंग

इस सेक्शन में, आपको Lit में टेंप्लेट बनाने के बुनियादी तरीके के बारे में जानकारी मिलेगी.

JSX और Lit टेंप्लेट

JSX, JavaScript का सिंटैक्स एक्सटेंशन है. इसकी मदद से, React के उपयोगकर्ता अपने JavaScript कोड में आसानी से टेंप्लेट लिख सकते हैं. Lit टेंप्लेट भी इसी तरह काम करते हैं: किसी कॉम्पोनेंट के यूज़र इंटरफ़ेस (यूआई) को उसकी स्थिति के फ़ंक्शन के तौर पर दिखाना.

बेसिक सिंटैक्स

React में, आपको JSX हैलो वर्ल्ड को इस तरह रेंडर करना होगा:

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
);

ऊपर दिए गए उदाहरण में, दो एलिमेंट और शामिल किया गया "name" वैरिएबल है. Lit में, आपको ये काम करने होंगे:

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 टेंप्लेट में कई एलिमेंट को ग्रुप करने के लिए, React फ़्रैगमेंट की ज़रूरत नहीं होती.

Lit में, टेंप्लेट को html टैग किए गए टेंप्लेट LITeral से रैप किया जाता है. यहीं से Lit को इसका नाम मिला है!

टेम्प्लेट मान

Lit टेंप्लेट में, अन्य Lit टेंप्लेट शामिल किए जा सकते हैं. इन्हें TemplateResult कहा जाता है. उदाहरण के लिए, name को इटैलिक (<i>) टैग में रैप करें और टैग किए गए टेंप्लेट लिटरल के साथ रैप करें ध्यान दें पक्का करें कि सिंगल कोट (') के बजाय, बैकटिक वर्ण (`) का इस्तेमाल किया जाए.

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 में ऐरे, स्ट्रिंग, अन्य TemplateResult के साथ-साथ निर्देश भी शामिल किए जा सकते हैं.

एक्सरसाइज़ के तौर पर, नीचे दिए गए React कोड को Lit में बदलने की कोशिश करें:

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
);

जवाब:

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
);

पासिंग और सेटिंग प्रॉप्स

JSX और Lit के सिंटैक्स के बीच का सबसे बड़ा अंतर, डेटा बाइंडिंग सिंटैक्स है. उदाहरण के लिए, बाइंडिंग के साथ यह React इनपुट लें:

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
);

ऊपर दिए गए उदाहरण में, एक इनपुट तय किया गया है, जो ये काम करता है:

  • किसी तय किए गए वैरिएबल के लिए बंद सेट किया जाता है (इस मामले में गलत)
  • क्लास को static-class के साथ-साथ एक वैरिएबल (इस मामले में "static-class my-class") पर सेट करता है
  • डिफ़ॉल्ट वैल्यू सेट करता है

लिट में आपको ये काम करने होंगे:

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 के उदाहरण में, disabled एट्रिब्यूट को टॉगल करने के लिए एक बूलियन बाइंडिंग जोड़ी गई है.

इसके बाद, className के बजाय सीधे class एट्रिब्यूट से बाइंडिंग होती है. class एट्रिब्यूट में एक से ज़्यादा बाइंडिंग जोड़ी जा सकती हैं. हालांकि, ऐसा तब तक नहीं किया जा सकता, जब तक classMap डायरेक्टिव का इस्तेमाल किया जा रहा हो. यह डायरेक्टिव, क्लास को टॉगल करने के लिए, जानकारी देने वाला हेल्पर है.

आखिर में, इनपुट पर value प्रॉपर्टी सेट कर दी जाती है. React के विपरीत, यह इनपुट एलिमेंट को रीड-ओनली के तौर पर सेट नहीं करेगा, क्योंकि यह इनपुट के नेटिव तरीके और व्यवहार का पालन करता है.

Lit प्रॉपर्टी बाइंडिंग सिंटैक्स

html`<my-element ?attribute-name=${booleanVar}>`;
  • किसी एलिमेंट पर एट्रिब्यूट को टॉगल करने के लिए, ? प्रीफ़िक्स बाइंडिंग सिंटैक्स है
  • inputRef.toggleAttribute('attribute-name', booleanVar) के बराबर
  • यह उन एलिमेंट के लिए काम का है जो disabled का इस्तेमाल करते हैं, क्योंकि डीओएम अब भी disabled="false" को 'सही' के तौर पर पढ़ता है, क्योंकि inputElement.hasAttribute('disabled') === true
html`<my-element .property-name=${anyVar}>`;
  • किसी एलिमेंट की प्रॉपर्टी सेट करने के लिए, . प्रीफ़िक्स बाइंडिंग सिंटैक्स है
  • inputRef.propertyName = anyVar के बराबर
  • ऑब्जेक्ट, कलेक्शन या क्लास जैसे जटिल डेटा को पास करने के लिए अच्छा
html`<my-element attribute-name=${stringVar}>`;
  • किसी एलिमेंट के एट्रिब्यूट से बाइंड करता है
  • inputRef.setAttribute('attribute-name', stringVar) के बराबर
  • बेसिक वैल्यू, स्टाइल के नियम चुनने वाले टूल, और क्वेरी सिलेक्टर के लिए सही है

पासिंग हैंडलर

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
);

ऊपर दिए गए उदाहरण में, एक इनपुट तय किया गया है, जो ये काम करता है:

  • इनपुट पर क्लिक करने के बाद, "क्लिक" शब्द को लॉग करें
  • जब उपयोगकर्ता कोई वर्ण टाइप करे, तब इनपुट की वैल्यू लॉग करें

लिट में आपको ये काम करने होंगे:

import {html, render} from 'lit';

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

render(
  element,
  mountNode
);

Lit के उदाहरण में, @click के साथ click इवेंट में एक लिसनर जोड़ा गया है.

इसके बाद, onChange का इस्तेमाल करने के बजाय, <input> के नेटिव input इवेंट के लिए बाइंडिंग है, क्योंकि नेटिव change इवेंट सिर्फ़ blur पर ट्रिगर होता है (इन इवेंट के बारे में ऐब्स्ट्रैक्ट प्रतिक्रिया दें).

Lit इवेंट हैंडलर सिंटैक्स

html`<my-element @event-name=${() => {...}}></my-element>`;
  • @ प्रीफ़िक्स, इवेंट लिसनर के लिए बाइंडिंग सिंटैक्स है
  • inputRef.addEventListener('event-name', ...) के बराबर
  • नेटिव डीओएम इवेंट के नामों का इस्तेमाल करता है

5. कॉम्पोनेंट और प्रॉप

इस सेक्शन में, आपको Lit क्लास के कॉम्पोनेंट और फ़ंक्शन के बारे में जानकारी मिलेगी. राज्य और हुक के बारे में विस्तार से बाद के सेक्शन में बताया गया है.

क्लास कॉम्पोनेंट और LitElement

React क्लास कॉम्पोनेंट के बराबर का Lit, LitElement है. साथ ही, Lit की "रिऐक्टिव प्रॉपर्टी" का कॉन्सेप्ट, React के प्रॉप और स्टेटस का कॉम्बिनेशन है. उदाहरण के लिए:

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
);

ऊपर दिए गए उदाहरण में एक React कॉम्पोनेंट है, जो:

  • name रेंडर करता है
  • name की डिफ़ॉल्ट वैल्यू को खाली स्ट्रिंग ("") पर सेट करता है
  • यह name, "Elliott" को फिर से असाइन करता है

LitElement में ऐसा करने का तरीका

TypeScript में:

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 में:

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);

और एचटीएमएल फ़ाइल में:

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

ऊपर दिए गए उदाहरण में क्या हो रहा है, इसकी समीक्षा:

@property({type: String})
name = '';
  • सार्वजनिक प्रतिक्रियाशील प्रॉपर्टी के बारे में बताता है – यह आपके कॉम्पोनेंट के सार्वजनिक एपीआई का हिस्सा होता है
  • यह आपके कॉम्पोनेंट पर डिफ़ॉल्ट रूप से, एक एट्रिब्यूट के साथ-साथ एक प्रॉपर्टी दिखाता है
  • कॉम्पोनेंट के एट्रिब्यूट (जो स्ट्रिंग होते हैं) को वैल्यू में बदलने का तरीका तय करता है
static get properties() {
  return {
    name: {type: String}
  }
}
  • यह @property TS डेकोरेटर की तरह ही काम करता है, लेकिन JavaScript में मूल रूप से चलता है
render() {
  return html`<h1>Hello, ${this.name}</h1>`
}
  • जब भी किसी रिएक्टिव प्रॉपर्टी में बदलाव होता है, तब इसे कहा जाता है
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
  ...
}
  • यह एचटीएमएल एलिमेंट टैग के नाम को क्लास की परिभाषा से जोड़ता है
  • कस्टम एलिमेंट स्टैंडर्ड की वजह से, टैग के नाम में हाइफ़न (-) शामिल होना चाहिए
  • LitElement में this, कस्टम एलिमेंट के इंस्टेंस का हवाला देता है (इस मामले में <welcome-banner>)
customElements.define('welcome-banner', WelcomeBanner);
  • यह @customElement TS डेकोरेटर के बराबर JavaScript है
<head>
  <script type="module" src="./index.js"></script>
</head>
  • कस्टम एलिमेंट की परिभाषा को इंपोर्ट करता है
<body>
  <welcome-banner name="Elliott"></welcome-banner>
</body>
  • पेज में कस्टम एलिमेंट जोड़ता है
  • name प्रॉपर्टी को 'Elliott' पर सेट करता है

फ़ंक्शन के कॉम्पोनेंट

Lit में फ़ंक्शन कॉम्पोनेंट का 1:1 मतलब नहीं है, क्योंकि यह JSX या प्रीप्रोसेसर का इस्तेमाल नहीं करता. हालांकि, ऐसा फ़ंक्शन कंपोज़ करना आसान है जो प्रॉपर्टी को लेता है और उन प्रॉपर्टी के आधार पर डीओएम को रेंडर करता है. उदाहरण के लिए:

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

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

लिट में यह होगा:

import {html, render} from 'lit';

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

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

6. स्थिति और लाइफ़साइकल

इस सेक्शन में, आपको Lit की स्थिति और लाइफ़साइकल के बारे में जानकारी मिलेगी.

स्थिति

Lit की "रिऐक्टिव प्रॉपर्टी" का कॉन्सेप्ट, React की स्टेट और प्रॉप का एक मिक्स है. रिऐक्टिव प्रॉपर्टी को बदलने पर, कॉम्पोनेंट का लाइफ़साइकल ट्रिगर हो सकता है. रिऐक्टिव प्रॉपर्टी दो वैरिएंट में आती हैं:

सार्वजनिक रिऐक्टिव प्रॉपर्टी

// 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 ने तय किया है
  • React के प्रॉप्स और स्टेट की तरह, लेकिन बदलाव किया जा सकता है
  • ऐसा सार्वजनिक एपीआई जिसे कॉम्पोनेंट के उपभोक्ता ऐक्सेस और सेट करते हैं

इंटरनल रिऐक्टिव स्टेट

// 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 ने तय किया
  • React की स्टेटस की तरह ही, लेकिन बदलाव किया जा सकता है
  • निजी इंटरनल स्टेटस, जिसे आम तौर पर कॉम्पोनेंट या सब-क्लास से ऐक्सेस किया जाता है

जीवनचक्र

Lit का लाइफ़साइकल, React के लाइफ़साइकल से काफ़ी मिलता-जुलता है. हालांकि, इनमें कुछ खास अंतर हैं.

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';
  }
}
  • लिटरल वैल्यू भी constructor है
  • सुपर कॉल में कुछ भी भेजने की ज़रूरत नहीं है
  • इनके ज़रिए ट्रिगर किया गया (पूरी सूची नहीं है):
    • document.createElement
    • document.innerHTML
    • new ComponentClass()
    • अगर पेज पर ऐसा टैग है जिसे अपग्रेड नहीं किया गया है और परिभाषा को @customElement या customElements.define के साथ लोड और रजिस्टर किया गया है
  • React के constructor फ़ंक्शन से मिलता-जुलता

render

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

// Lit
render() {
  return html`<div>Hello World</div>`;
}
  • लिटरल वैल्यू भी render है
  • रेंडर किया जा सकने वाला कोई भी नतीजा दिखा सकता है, जैसे कि TemplateResult या string वगैरह.
  • React की तरह ही, render() भी पूरी तरह से फ़ंक्शन होना चाहिए
  • createRenderRoot() जो भी नोड दिखाएगा उस पर रेंडर होगा (डिफ़ॉल्ट रूप से ShadowRoot)

componentDidMount

componentDidMount, Lit के firstUpdated और connectedCallback लाइफ़साइकल कॉलबैक, दोनों के कॉम्बिनेशन की तरह होता है.

firstUpdated

import Chart from 'chart.js';

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

// Lit
firstUpdated() {
  this._chart = new Chart(this.chartEl, {...});
}
  • इसे पहली बार तब कॉल किया जाता है, जब कॉम्पोनेंट के टेंप्लेट को कॉम्पोनेंट के रूट में रेंडर किया जाता है
  • यह सिर्फ़ तब कॉल किया जाएगा, जब एलिमेंट कनेक्ट हो. उदाहरण के लिए, जब तक उस नोड को डीओएम ट्री में जोड़ा नहीं जाता, तब तक document.createElement('my-component') के ज़रिए कॉल नहीं किया जाएगा
  • यह कॉम्पोनेंट सेटअप करने के लिए एक अच्छी जगह है. इसके लिए, कॉम्पोनेंट के डीओएम की ज़रूरत होती है
  • firstUpdated की रिऐक्टिव प्रॉपर्टी में React के componentDidMount बदलाव से अलग, फिर से रेंडर होगा. हालांकि, ब्राउज़र आम तौर पर बदलावों को एक ही फ़्रेम में बैच बनाकर देगा. अगर उन बदलावों के लिए रूट के DOM का ऐक्सेस ज़रूरी नहीं है, तो आम तौर पर उन्हें willUpdate में डाला जाना चाहिए

connectedCallback

// React
componentDidMount() {
  this.window.addEventListener('resize', this.boundOnResize);
}

// Lit
connectedCallback() {
  super.connectedCallback();
  this.window.addEventListener('resize', this.boundOnResize);
}
  • जब भी कस्टम एलिमेंट को DOM ट्री में डाला जाता है, तब इसे कॉल किया जाता है
  • React कॉम्पोनेंट के उलट, जब कस्टम एलिमेंट डीओएम से अलग किए जाते हैं, तो वे खत्म नहीं होते और इस तरह वे कई बार "कनेक्ट" हो सकते हैं
    • firstUpdated को फिर से कॉल नहीं किया जाएगा
  • डीओएम को फिर से शुरू करने या डिसकनेक्ट होने पर हटाए गए इवेंट लिसनर को फिर से अटैच करने के लिए काम का
  • ध्यान दें: connectedCallback को firstUpdated से पहले कॉल किया जा सकता है, इसलिए पहली कॉल पर DOM उपलब्ध नहीं हो सकता है

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);
  }
}
  • अंग्रेज़ी के छोटे से "अपडेट" काल का इस्तेमाल करके, updated इसके बराबर है
  • React के उलट, updated को शुरुआती रेंडर पर भी कॉल किया जाता है
  • रिऐक्ट के componentDidUpdate के फ़ंक्शन में मिलता-जुलता

componentWillUnmount

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

// Lit
disconnectedCallback() {
  super.disconnectedCallback();
  this.window.removeEventListener('resize', this.boundOnResize);
}
  • लिटरल वैल्यू disconnectedCallback से मिलती-जुलती है
  • React कॉम्पोनेंट के उलट, जब कस्टम एलिमेंट को डीओएम से अलग किया जाता है, तो कॉम्पोनेंट नष्ट नहीं होता
  • componentWillUnmount के उलट, एलिमेंट को ट्री से हटाने के बाद disconnectedCallback को कहा जाता है
  • रूट के अंदर का DOM अब भी रूट की सबट्री से जुड़ा है
  • इवेंट लिसनर और लीकी रेफ़रंस को हटाने के लिए काम का है, ताकि ब्राउज़र कॉम्पोनेंट को ग़ैर-ज़रूरी डेटा से हटा सके

कसरत

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')
);

ऊपर दिए गए उदाहरण में, एक साधारण घड़ी है जो ये काम करती है:

  • यह "नमस्ते दुनिया के लोगों! यह समय है" और फिर यह समय दिखाता है
  • हर सेकंड, घड़ी का समय अपडेट हो जाएगा
  • डिसमाунт होने पर, यह टिक को कॉल करके इंटरवल को मिटा देता है

सबसे पहले कॉम्पोनेंट क्लास का एलान करें:

// 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);

इसके बाद, date को शुरू करें और इसे @state के साथ इंटरनल रिऐक्टिव प्रॉपर्टी के तौर पर घोषित करें. ऐसा इसलिए, क्योंकि कॉम्पोनेंट के उपयोगकर्ता सीधे तौर पर date को सेट नहीं करेंगे.

// 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);

इसके बाद, टेंप्लेट रेंडर करें.

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

अब, सही के निशान वाला तरीका लागू करें.

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

इसके बाद, componentDidMount को लागू करने की ज़रूरत है. फिर से बता दें कि Lit ऐनालॉग firstUpdated और connectedCallback का मिला-जुला रूप है. इस कॉम्पोनेंट के मामले में, tick को setInterval के साथ कॉल करने के लिए, रूट के अंदर के DOM को ऐक्सेस करने की ज़रूरत नहीं होती. इसके अलावा, दस्तावेज़ ट्री से एलिमेंट हटाने पर इंटरवल हट जाएगा. इसलिए, अगर उसे फिर से अटैच किया जाता है, तो इंटरवल फिर से शुरू करना होगा. इसलिए, यहां connectedCallback एक बेहतर विकल्प है.

// 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
  );
}

आखिर में, इंटरवल को साफ़ करें, ताकि दस्तावेज़ ट्री से एलिमेंट के डिसकनेक्ट होने के बाद, यह टिक न चलाए.

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

सभी चीज़ों को मिलाकर, यह कुछ ऐसा दिखेगा:

// 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. Hooks

इस सेक्शन में, आपको React Hook के कॉन्सेप्ट को Lit में ट्रांसलेट करने का तरीका पता चलेगा.

React हुक के कॉन्सेप्ट

React हुक, फ़ंक्शन कॉम्पोनेंट को स्टेटस में "हुक" करने का एक तरीका उपलब्ध कराते हैं. इसके कई फ़ायदे हैं.

  • ये स्टेटफ़ुल लॉजिक के फिर से इस्तेमाल को आसान बनाते हैं
  • कॉम्पोनेंट को छोटे फ़ंक्शन में बांटने में मदद करता है

इसके अलावा, फ़ंक्शन पर आधारित कॉम्पोनेंट पर फ़ोकस करने से, React के क्लास-आधारित सिंटैक्स से जुड़ी कुछ समस्याओं का पता चला. जैसे:

  • props को constructor से super में पास करना
  • constructor
      में प्रॉपर्टी का सही से शुरू होना
    • उस समय React टीम ने इसी वजह से इसे हल कर लिया था, लेकिन ES2019 ने इसे हल कर दिया
  • this की वजह से होने वाली समस्याएं, अब कॉम्पोनेंट से जुड़ी नहीं हैं

Lit में React हुक के कॉन्सेप्ट

कॉम्पोनेंट और प्रॉप सेक्शन में बताया गया है कि Lit, किसी फ़ंक्शन से कस्टम एलिमेंट बनाने का तरीका नहीं देता. हालांकि, LitElement, React क्लास कॉम्पोनेंट से जुड़ी ज़्यादातर मुख्य समस्याओं को हल करता है. उदाहरण के लिए:

// 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 इन समस्याओं को कैसे हल करता है?

  • constructor कोई तर्क नहीं लेता
  • सभी @event बाइंडिंग, this से अपने-आप बाइंड हो जाती हैं
  • ज़्यादातर मामलों में this, कस्टम एलिमेंट के रेफ़रंस को दिखाता है
  • क्लास की प्रॉपर्टी को अब क्लास के सदस्यों के तौर पर इंस्टैंशिएट किया जा सकता है. इससे, कंस्ट्रक्टर पर आधारित लागू करने की सुविधा को हटा दिया जाता है

रिऐक्टिव कंट्रोल

हुक के पीछे के मुख्य कॉन्सेप्ट, Lit में रिऐक्टिव कंट्रोलर के तौर पर मौजूद हैं. रिऐक्टिव कंट्रोलर पैटर्न की मदद से, स्टेटफ़ुल लॉजिक शेयर किया जा सकता है. साथ ही, कॉम्पोनेंट को छोटे और ज़्यादा मॉड्यूलर बिट में बांटा जा सकता है. इसके अलावा, किसी एलिमेंट के अपडेट लाइफ़साइकल में भी बदलाव किया जा सकता है.

रिऐक्टिव कंट्रोलर एक ऑब्जेक्ट इंटरफ़ेस है, जो LitElement जैसे कंट्रोलर होस्ट के अपडेट लाइफ़साइकल में शामिल हो सकता है.

ReactiveController और reactiveControllerHost की लाइफ़साइकल इस तरह की होती है:

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>;
}

एक रिऐक्टिव कंट्रोलर बनाकर और उसे addController के साथ किसी होस्ट से अटैच करने पर, कंट्रोलर के लाइफ़साइकल को होस्ट के साथ कॉल किया जाएगा. उदाहरण के लिए, स्टेटस और लाइफ़साइकल सेक्शन में दिए गए घड़ी के उदाहरण को याद करें:

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')
);

ऊपर दिए गए उदाहरण में, एक साधारण घड़ी दिखाई गई है, जो ये काम करती है:

  • यह "नमस्ते दुनिया के लोगों! यह समय है" और फिर यह समय दिखाता है
  • हर सेकंड, घड़ी का समय अपडेट हो जाएगा
  • अलग करने पर, यह टिक को कॉल करने वाले इंटरवल को हटा देता है

कॉम्पोनेंट स्कैफ़ोल्डिंग बनाना

सबसे पहले कॉम्पोनेंट क्लास का एलान करना शुरू करें और फिर render फ़ंक्शन जोड़ें.

// 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);

कंट्रोलर बनाना

अब clock.ts पर स्विच करें और ClockController के लिए क्लास बनाएं और constructor सेट अप करें:

// 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 इंटरफ़ेस शेयर करता हो. हालांकि, Lit टीम ज़्यादातर बुनियादी मामलों में, constructor के साथ ऐसी क्लास का इस्तेमाल करना पसंद करती है जो ReactiveControllerHost इंटरफ़ेस के साथ-साथ, कंट्रोलर को शुरू करने के लिए ज़रूरी अन्य प्रॉपर्टी भी ले सकती है.

अब आपको React लाइफ़साइकल कॉलबैक को कंट्रोलर कॉलबैक में बदलना होगा. कम शब्दों में कहें:

  • componentDidMount
    • LitElement के connectedCallback में
    • कंट्रोलर के hostConnected में
  • ComponentWillUnmount
    • LitElement के disconnectedCallback पर
    • कंट्रोलर के hostDisconnected में

रिऐक्ट लाइफ़साइकल को लिटिल लाइफ़साइकल में अनुवाद करने के बारे में ज़्यादा जानकारी के लिए, राज्य और लाइफ़साइकल सेक्शन देखें.

इसके बाद, hostConnected कॉलबैक और tick तरीके लागू करें. साथ ही, hostDisconnected में इंटरवल को ठीक करें, जैसा कि स्टेटस और लाइफ़साइकल सेक्शन में दिए गए उदाहरण में किया गया है.

// 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);
  }
}

कंट्रोलर का इस्तेमाल करना

क्लॉक कंट्रोलर का इस्तेमाल करने के लिए, कंट्रोलर को इंपोर्ट करें. इसके बाद, index.ts या index.js में कॉम्पोनेंट को अपडेट करें.

// 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);

कंट्रोलर का इस्तेमाल करने के लिए, आपको कंट्रोलर होस्ट (जो कि <my-element> कॉम्पोनेंट है) का रेफ़रंस पास करके, कंट्रोलर को इंस्टैंशिएट करना होगा. इसके बाद, render तरीके में कंट्रोलर का इस्तेमाल करना होगा.

कंट्रोलर में फिर से रेंडर करने की सुविधा को ट्रिगर करना

ध्यान दें कि इसमें समय दिखाया जाएगा, लेकिन समय अपडेट नहीं हो रहा है. ऐसा इसलिए होता है, क्योंकि कंट्रोलर हर सेकंड तारीख सेट कर रहा है, लेकिन होस्ट अपडेट नहीं हो रहा है. ऐसा इसलिए है, क्योंकि date अब कॉम्पोनेंट के बजाय ClockController क्लास में बदल रहा है. इसका मतलब है कि कंट्रोलर पर date सेट होने के बाद, होस्ट को host.requestUpdate() के साथ अपडेट लाइफ़साइकल चलाने के लिए कहा जाना चाहिए.

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

अब समय सुलझना चाहिए!

हुक के साथ सामान्य इस्तेमाल के उदाहरणों की ज़्यादा गहराई से तुलना करने के लिए, कृपया बेहतर विषय - हुक सेक्शन देखें.

8. बच्चे

इस सेक्शन में, आपको लिटरेचर में बच्चों को मैनेज करने के लिए स्लॉट इस्तेमाल करने का तरीका बताया जाएगा.

स्लॉट और बच्चे

स्लॉट की मदद से, कॉम्पोनेंट को नेस्ट किया जा सकता है. इससे कॉम्पोनेंट को एक साथ जोड़ा जा सकता है.

प्रतिक्रिया में, बच्चों को चीज़ों से मिलती-जुलती चीज़ें मिलती हैं. डिफ़ॉल्ट स्लॉट props.children होता है और render फ़ंक्शन से यह तय होता है कि डिफ़ॉल्ट स्लॉट कहां है. उदाहरण के लिए:

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

ध्यान रखें कि props.children, React कॉम्पोनेंट हैं, न कि एचटीएमएल एलिमेंट.

Lit में, स्लॉट एलिमेंट की मदद से, रेंडर फ़ंक्शन में चाइल्ड एलिमेंट बनाए जाते हैं. ध्यान दें कि बच्चों को रिऐक्ट की तरह इनहेरिट नहीं किया जाता. लिट में, चिल्ड्रन स्लॉट में HTMLElements होते हैं. इस अटैचमेंट को प्रक्षेपण कहा जाता है.

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

एक से ज़्यादा स्लॉट

React में, कई स्लॉट जोड़ना ज़रूरी है, जो कि ज़्यादा प्रॉपर्टी को इनहेरिट करने जैसा ही होता है.

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

इसी तरह, <slot> एलिमेंट ज़्यादा जोड़ने पर, Lit में ज़्यादा स्लॉट बनते हैं. name एट्रिब्यूट के साथ एक से ज़्यादा स्लॉट तय किए गए हैं: <slot name="slot-name">. इससे बच्चे यह तय कर सकते हैं कि उन्हें कौनसा स्लॉट असाइन किया जाएगा.

@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>
   `;
  }
}

डिफ़ॉल्ट स्लॉट कॉन्टेंट

जब उस स्लॉट में कोई नोड प्रोजेक्ट नहीं किया जाएगा, तब स्लॉट अपना सबट्री दिखाएंगे. जब किसी स्लॉट में नोड प्रोजेक्ट किए जाते हैं, तो वह स्लॉट अपना सबट्री नहीं दिखाएगा. इसके बजाय, प्रोजेक्ट किए गए नोड दिखाएगा.

@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>
   `;
  }
}

बच्चों को स्लॉट असाइन करें

प्रतिक्रिया में, बच्चों को कॉम्पोनेंट की प्रॉपर्टी के ज़रिए स्लॉट असाइन किए जाते हैं. नीचे दिए गए उदाहरण में, प्रतिक्रिया देने वाले एलिमेंट को headerChildren और sectionChildren प्रॉपर्टी में पास किया गया है.

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

Lit में, slot एट्रिब्यूट का इस्तेमाल करके बच्चों को स्लॉट असाइन किए जाते हैं.

@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>
   `;
  }
}

अगर कोई डिफ़ॉल्ट स्लॉट (जैसे कि <slot>) न हो और ऐसा कोई भी स्लॉट न हो जिसमें कस्टम एलिमेंट के चिल्ड्रेन के slot एट्रिब्यूट (उदाहरण के लिए, <div slot="foo">) से मेल खाने वाला name एट्रिब्यूट (उदाहरण के लिए, <slot name="foo">) हो, तो वह नोड प्रोजेक्ट न किया जाए और न ही दिखे.

9. रेफ़रंस

कभी-कभी, किसी डेवलपर को एचटीएमएल एलिमेंट के एपीआई को ऐक्सेस करना पड़ सकता है.

इस सेक्शन में, आपको Lit में एलिमेंट के रेफ़रंस पाने का तरीका पता चलेगा.

React के रेफ़रंस

React कॉम्पोनेंट को फ़ंक्शन कॉल की एक सीरीज़ में ट्रांसपाइल किया जाता है. इन फ़ंक्शन कॉल को ट्रिगर करने पर, वर्चुअल डीओएम बनता है. इस वर्चुअल डीओएम को ReactDOM स्वीकार करता है और HTMLElements को रेंडर करता है.

React में, रेफ़रंस के तौर पर मेमोरी में सेव किया गया HTMLElement शामिल करने की जगह होती है.

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>
 );
};

ऊपर दिए गए उदाहरण में, प्रतिक्रिया देने वाला कॉम्पोनेंट ये काम करेगा:

  • खाली टेक्स्ट इनपुट और टेक्स्ट वाले बटन को रेंडर करना
  • बटन पर क्लिक होने पर इनपुट पर फ़ोकस करें

पहली बार रेंडर होने के बाद React, ref एट्रिब्यूट का इस्तेमाल करके inputRef.current को जनरेट किए गए HTMLInputElement पर सेट कर देगा.

@query के साथ "रेफ़रंस" ली गई

Lit, ब्राउज़र के आस-पास रहता है और मूल ब्राउज़र सुविधाओं के बारे में बहुत ही छोटा एब्सट्रैक्ट बनाता है.

Lit में refs के बराबर React, @query और @queryAll डेकोरेटर से मिला एचटीएमएल एलिमेंट है.

@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>
   `;
  }
}

ऊपर दिए गए उदाहरण में, Lit कॉम्पोनेंट ये काम करता है:

  • @query डेकोरेटर (HTMLInputElement के लिए गैटर बनाना) का इस्तेमाल करके, MyElement पर प्रॉपर्टी के बारे में बताता है.
  • onButtonClick नाम के एक क्लिक इवेंट कॉलबैक का एलान करता है और उसे अटैच करता है.
  • बटन पर क्लिक करने पर इनपुट पर फ़ोकस करता है

JavaScript में, @query और @queryAll डेकोरेटर querySelector और querySelectorAll की परफ़ॉर्मेंस देते हैं. यह @query('input') inputEl!: HTMLInputElement; के बराबर की JavaScript है

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

Lit कॉम्पोनेंट, render तरीके के टेंप्लेट को my-element के रूट में कमिट करने के बाद, @query डेकोरेटर अब inputEl को रेंडर रूट में मिला पहला input एलिमेंट दिखाने की अनुमति देगा. अगर @query को बताया गया एलिमेंट नहीं मिलता, तो यह null वैल्यू दिखाएगा.

अगर रेंडर रूट में एक से ज़्यादा input एलिमेंट थे, तो @queryAll नोड की सूची दिखाएगा.

10. मध्यस्थता स्थिति

इस सेक्शन में, आपको Lit में कॉम्पोनेंट के बीच स्टेट को मीडिएट करने का तरीका पता चलेगा.

फिर से इस्तेमाल किए जा सकने वाले कॉम्पोनेंट

टॉप डाउन डेटा फ़्लो के साथ, काम करने वाले रेंडरिंग पाइपलाइन की तरह प्रतिक्रिया देता है. माता-पिता, प्रॉप की मदद से बच्चों को स्टेटस देते हैं. प्रॉप में मिलने वाले कॉलबैक के ज़रिए बच्चे, माता-पिता से बातचीत करते हैं.

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


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

ऊपर दिए गए उदाहरण में, प्रतिक्रिया देने वाला एक कॉम्पोनेंट ये काम करता है:

  • props.step वैल्यू के आधार पर लेबल बनाता है.
  • +step या -step को लेबल के तौर पर इस्तेमाल करके बटन रेंडर करता है
  • क्लिक करने पर, पैरंट कॉम्पोनेंट को अपडेट करता है. इसके लिए, props.step को आर्ग्युमेंट के तौर पर इस्तेमाल करके props.addToCounter को कॉल करता है

Lit में कॉलबैक पास किए जा सकते हैं, लेकिन इसके लिए सामान्य पैटर्न अलग होते हैं. ऊपर दिए गए उदाहरण में मौजूद React कॉम्पोनेंट को, नीचे दिए गए उदाहरण में Lit कॉम्पोनेंट के तौर पर लिखा जा सकता है:

@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>
    `;
  }
}

ऊपर दिए गए उदाहरण में, लिट कॉम्पोनेंट ये काम करेगा:

  • रीऐक्टिव प्रॉपर्टी step बनाएं
  • क्लिक करने पर, एलिमेंट की step वैल्यू को update-counter नाम के कस्टम इवेंट में भेजना

ब्राउज़र इवेंट, चाइल्ड से पैरंट एलिमेंट तक बबल अप होते हैं. इवेंट की मदद से बच्चे, इंटरैक्शन से जुड़े इवेंट और स्थिति में हुए बदलावों को ब्रॉडकास्ट कर सकते हैं. दरअसल, रिऐक्ट की स्थिति बिलकुल उलट होती है. इसलिए, यह आम बात नहीं है कि रिऐक्ट कॉम्पोनेंट्स को डिस्पैच होते हुए देखा जा सकता है और इवेंट को लिट कॉम्पोनेंट की तरह ही सुना जा सकता है.

स्टेटफ़ुल कॉम्पोनेंट

React में, स्टेट मैनेज करने के लिए हुक का इस्तेमाल करना आम बात है. CounterButton कॉम्पोनेंट का फिर से इस्तेमाल करके, MyCounter कॉम्पोनेंट बनाया जा सकता है. ध्यान दें कि addToCounter को CounterButton के दोनों इंस्टेंस में कैसे पास किया जाता है.

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>
 );
};

ऊपर दिए गए उदाहरण में ये काम किए गए हैं:

  • count स्थिति सेट करता है.
  • ऐसा कॉलबैक बनाता है जो count स्टेट में नंबर जोड़ता है.
  • CounterButton हर क्लिक पर step से count को अपडेट करने के लिए, addToCounter का इस्तेमाल करता है.

MyCounter को लागू करने की ऐसी ही एक प्रोसेस, Lit में लागू की जा सकती है. ध्यान दें कि counter-button को addToCounter कैसे पास नहीं किया जाता. इसके बजाय, कॉलबैक को पैरंट एलिमेंट पर @update-counter इवेंट के लिए, इवेंट लिसनर के तौर पर बाउंड किया जाता है.

@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>
    `;
  }
}

ऊपर दिया गया उदाहरण ये काम करता है:

  • count नाम की एक रिऐक्टिव प्रॉपर्टी बनाता है, जो वैल्यू बदलने पर कॉम्पोनेंट को अपडेट करेगी
  • यह addToCounter कॉलबैक को @update-counter इवेंट लिसनर से बाइंड करता है
  • update-counter इवेंट के detail.step में मिली वैल्यू को जोड़कर, count को अपडेट करता है
  • step एट्रिब्यूट की मदद से, counter-button की step वैल्यू सेट करता है

माता-पिता के बदलावों को बच्चों में ब्रॉडकास्ट करने के लिए, Lit में रिऐक्टिव प्रॉपर्टी इस्तेमाल करना ज़्यादा आसान है. इसी तरह, ब्राउज़र के इवेंट सिस्टम का इस्तेमाल करके, जानकारी को नीचे से ऊपर की ओर बबल करने का तरीका भी अच्छा है.

यह तरीका, सबसे सही तरीकों का पालन करता है. साथ ही, यह वेब कॉम्पोनेंट के लिए क्रॉस-प्लैटफ़ॉर्म सहायता उपलब्ध कराने के Lit के लक्ष्य का पालन करता है.

11. शैलीकृत करना

इस सेक्शन में, आपको Lit में स्टाइलिंग के बारे में जानकारी मिलेगी.

शैलीकृत करना

Lit, एलिमेंट को स्टाइल करने के कई तरीके उपलब्ध कराता है. साथ ही, इसमें पहले से मौजूद समाधान भी मौजूद है.

इनलाइन स्टाइल

Lit, इनलाइन स्टाइल के साथ-साथ उन्हें बाइंड करने की सुविधा देता है.

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>
    `;
  }
}

ऊपर दिए गए उदाहरण में इनलाइन स्टाइल के साथ दो हेडिंग हैं.

अब border-color.js से ऑरेंज टेक्स्ट में बॉर्डर इंपोर्ट और बाइंड करें:

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

...

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

हर बार स्टाइल स्ट्रिंग को कैलकुलेट करने से परेशानी हो सकती है. इसलिए, Lit इस काम में मदद करने के लिए निर्देश देता है.

styleMap

styleMap डायरेक्टिव की मदद से, इनलाइन स्टाइल सेट करने के लिए JavaScript का इस्तेमाल करना आसान हो जाता है. उदाहरण के लिए:

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>
    `;
  }
}

ऊपर दिया गया उदाहरण ये काम करता है:

  • बॉर्डर और कलर पिकर के साथ h1 दिखाता है
  • border-color को कलर पिकर से चुनी गई वैल्यू में बदलता है

इसके अलावा, styleMap भी है, जिसका इस्तेमाल h1 की स्टाइल सेट करने के लिए किया जाता है. styleMap, React के style एट्रिब्यूट बाइंडिंग सिंटैक्स से मिलता-जुलता सिंटैक्स फ़ॉलो करता है.

CSSResult

कॉम्पोनेंट को स्टाइल करने का सुझाया गया तरीका, टैग किए गए css टेंप्लेट का लिटरल इस्तेमाल करना है.

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>
    `;
  }
}

ऊपर दिए गए उदाहरण में ये काम किए गए हैं:

  • बाइंडिंग के साथ सीएसएस टैग किया गया टेंप्लेट लिटरल दिखाता है
  • आईडी वाले दो h1 के रंग सेट करता है

css टेंप्लेट टैग को इस्तेमाल करने के फ़ायदे:

  • हर क्लास बनाम हर इंस्टेंस के लिए एक बार पार्स किया जाता है
  • मॉड्यूल को फिर से इस्तेमाल करने के मकसद से लागू किया गया
  • स्टाइल को आसानी से अलग-अलग फ़ाइलों में बांटा जा सकता है
  • सीएसएस कस्टम प्रॉपर्टी के लिए पॉलीफ़िल के साथ काम करता है

इसके अलावा, index.html में <style> टैग पर ध्यान दें:

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

Lit, आपके कॉम्पोनेंट की स्टाइल को उनके रूट तक पहुंचाएगा. इसका मतलब है कि स्टाइल, अंदर और बाहर लीक नहीं होंगे. सभी कॉम्पोनेंट के बीच स्टाइल पास करने के लिए, Lit टीम सीएसएस की कस्टम प्रॉपर्टी का इस्तेमाल करने का सुझाव देती है. इससे, वे लिटिल स्टाइल स्कोपिंग में शामिल हो सकते हैं.

शैली टैग

अपने टेंप्लेट में <style> टैग को इनलाइन भी किया जा सकता है. ब्राउज़र इन स्टाइल टैग को डुप्लीकेट नहीं होने देगा. हालांकि, इन्हें अपने टेंप्लेट में डालने पर, इन्हें हर कॉम्पोनेंट इंस्टेंस के हिसाब से पार्स किया जाएगा, न कि हर क्लास के हिसाब से, जैसा कि css टैग वाले टेंप्लेट के मामले में होता है. इसके अलावा, ब्राउज़र में CSSResult की डुप्लीकेट कॉपी हटाने की तकनीक ज़्यादा तेज़ी से काम करती है.

अपने टेंप्लेट में <link rel="stylesheet"> का इस्तेमाल करने से, स्टाइल भी बनाए जा सकते हैं. हालांकि, हमारा सुझाव है कि ऐसा न करें, क्योंकि इससे बिना स्टाइल वाले कॉन्टेंट (एफ़ओयूसी) का शुरुआती फ़्लैश शुरू हो सकता है.

12. बेहतर विषय (ज़रूरी नहीं)

JSX और टेंप्लेट

लिटिल और वर्चुअल डीओएम

Lit-html में ऐसा कंवेंशनल वर्चुअल DOM शामिल नहीं है जो हर नोड में अंतर करता है. इसके बजाय, यह ES2015 के टैग किए गए टेंप्लेट लिटरल स्पेसिफ़िकेशन में मौजूद परफ़ॉर्मेंस की सुविधाओं का इस्तेमाल करता है. टैग किए गए टेंप्लेट लिटरल, टेंप्लेट लिटरल स्ट्रिंग होती हैं जिनमें टैग फ़ंक्शन जुड़े होते हैं.

टेंप्लेट लिटरल का एक उदाहरण यहां दिया गया है:

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

यहां टैग किए गए टेंप्लेट का एक उदाहरण दिया गया है:

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

ऊपर दिए गए उदाहरण में, टैग tag फ़ंक्शन है और f फ़ंक्शन, टैग किए गए टेंप्लेट लिटरल को कॉल करता है.

Lit में परफ़ॉर्मेंस की काफ़ी बेहतरी इस बात से होती है कि टैग फ़ंक्शन में पास की गई स्ट्रिंग ऐरे का पॉइंटर एक ही होता है (जैसा कि दूसरे console.log में दिखाया गया है). ब्राउज़र, हर टैग फ़ंक्शन के आह्वान पर नया strings ऐरे फिर से नहीं बनाता, क्योंकि वह एक ही टेंप्लेट लिटरल का इस्तेमाल कर रहा होता है. इसका मतलब है कि वह एएसटी में एक ही जगह पर मौजूद होता है. इसलिए, Lit की बाइंडिंग, पार्स करने, और टेंप्लेट की कैश मेमोरी में बदलाव करने की सुविधा, इन सुविधाओं का फ़ायदा ले सकती है. इसके लिए, रनटाइम के दौरान ज़्यादा खर्च नहीं करना पड़ता.

टैग किए गए टेंप्लेट के लिटरल बिल्ट-इन ब्राउज़र व्यवहार से Lit को परफ़ॉर्मेंस में काफ़ी फ़ायदा मिलता है. ज़्यादातर पारंपरिक वर्चुअल DOM, ज़्यादातर काम JavaScript में करते हैं. हालांकि, टैग किए गए टेंप्लेट लिटरल, ब्राउज़र के C++ में ज़्यादातर अंतर करते हैं.

अगर आपको React या Preact के साथ, एचटीएमएल टैग किए गए टेंप्लेट के लिटरल इस्तेमाल करना है, तो Lit टीम htm लाइब्रेरी का सुझाव देती है.

हालांकि, जैसा कि Google Codelabs और कई ऑनलाइन कोड एडिटर के मामले में होता है, टैग किए गए टेंप्लेट का लिटरल सिंटैक्स हाइलाइट करने का तरीका आम नहीं है. कुछ आईडीई और टेक्स्ट एडिटर, डिफ़ॉल्ट रूप से इनके साथ काम करते हैं. जैसे, Atom और GitHub का कोडब्लॉक हाइलाइटर. Lit की टीम, कम्यूनिटी के साथ मिलकर भी काम करती है, ताकि lit-plugin जैसे प्रोजेक्ट को बनाए रखा जा सके. यह एक VS Code प्लग इन है, जो आपके Lit प्रोजेक्ट में सिंटैक्स हाइलाइटिंग, टाइप की जांच, और इंटेलिसेंस की सुविधा जोड़ेगा.

Lit &JSX + प्रतिक्रिया DOM

JSX ब्राउज़र में नहीं चलता है और इसके बजाय, वह JSX को JavaScript फ़ंक्शन कॉल (आम तौर पर, बेबेल के ज़रिए) में बदलने के लिए प्रीप्रोसेसर का इस्तेमाल करता है.

उदाहरण के लिए, बेबल इसे बदल देगा:

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

में बदला जा सकता है:

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

इसके बाद, React DOM आउटपुट देता है और उसे असल डीओएम में बदल देता है. इसमें प्रॉपर्टी, एट्रिब्यूट, इवेंट लिसनर वगैरह शामिल हैं.

Lit-html, टैग किए गए टेंप्लेट लिटरल का इस्तेमाल करता है. ये टेंप्लेट लिटरल, ब्राउज़र में ट्रांसपाइलेशन या प्रीप्रोसेसर के बिना चल सकते हैं. इसका मतलब है कि Lit का इस्तेमाल शुरू करने के लिए, आपको सिर्फ़ एक एचटीएमएल फ़ाइल, एक ES मॉड्यूल स्क्रिप्ट, और एक सर्वर की ज़रूरत होगी. यहां पूरी तरह से ब्राउज़र पर चलने वाली स्क्रिप्ट दी गई है:

<!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>

साथ ही, Lit का टेंप्लेटिंग सिस्टम, lit-html, जो पारंपरिक वर्चुअल DOM का इस्तेमाल नहीं करता, बल्कि सीधे DOM API का इस्तेमाल करता है. इसलिए, Lit 2 का साइज़ React (2.8kb) + React (2.8kb) + प्रतिक्रिया-डॉम (39.4kb) की तुलना में gzip किया गया और छोटा किया गया है.

इवेंट

React, सिंथेटिक इवेंट सिस्टम का इस्तेमाल करता है. इसका मतलब है कि प्रतिक्रिया-डॉम को हर वह इवेंट तय करना चाहिए जिसका इस्तेमाल हर कॉम्पोनेंट पर किया जाएगा. साथ ही, हर तरह के नोड के लिए CamlCase इवेंट लिसनर उपलब्ध कराता है. इस वजह से, JSX में कस्टम इवेंट के लिए इवेंट लिसनर तय करने का कोई तरीका नहीं है. इसलिए, डेवलपर को ref का इस्तेमाल करना होगा और फिर लिसनर को लागू करना होगा. इससे, उन लाइब्रेरी को इंटिग्रेट करने पर डेवलपर का अनुभव बेहतर होता है जो React का इस्तेमाल न करती हों. इससे, आपको React के हिसाब से रैपर लिखना पड़ता है.

Lit-html सीधे तौर पर DOM को ऐक्सेस करता है और नेटिव इवेंट का इस्तेमाल करता है. इसलिए, इवेंट लिसनर जोड़ना @event-name=${eventNameListener} जितना आसान है. इसका मतलब है कि इवेंट लिसनर जोड़ने के साथ-साथ इवेंट ट्रिगर करने के लिए, कम रनटाइम पार्सिंग की जाती है.

कॉम्पोनेंट और प्रॉप

प्रतिक्रिया देने वाले कॉम्पोनेंट और कस्टम एलिमेंट

हुड के तहत, LitElement ने अपने कॉम्पोनेंट को पैकेज करने के लिए कस्टम एलिमेंट का इस्तेमाल किया है. कस्टम एलिमेंट, कॉम्पोनेंटाइज़ेशन के मामले में, React कॉम्पोनेंट के बीच कुछ अंतर कर देते हैं. राज्य और लाइफ़साइकल सेक्शन में, स्थिति और लाइफ़साइकल के बारे में ज़्यादा जानकारी दी गई है.

कॉम्पोनेंट सिस्टम के तौर पर, कस्टम एलिमेंट के कुछ फ़ायदे ये हैं:

  • ये ब्राउज़र के नेटिव होते हैं और इनके लिए किसी टूल की ज़रूरत नहीं होती
  • innerHTML और document.createElement से लेकर querySelector तक के हर ब्राउज़र एपीआई के साथ काम करता है
  • आम तौर पर, सभी फ़्रेमवर्क में इस्तेमाल किया जा सकता है
  • customElements.define और "हाइड्रेट" DOM के साथ, लेट-लॉकेशन रजिस्टर किया जा सकता है

React कॉम्पोनेंट की तुलना में, कस्टम एलिमेंट के कुछ नुकसान:

  • क्लास परिभाषित किए बिना कस्टम एलिमेंट नहीं बनाया जा सकता (इसलिए, JSX जैसा कोई फ़ंक्शनल कॉम्पोनेंट नहीं है)
  • क्लोज़िंग टैग
      होना चाहिए
    • ध्यान दें: इसके बावजूद, डेवलपर की सुविधा वाले ब्राउज़र वेंडर को अपने-आप बंद होने वाले टैग की खास बातों पर पछतावा होता है. इसलिए, नए स्पेसिफ़िकेशन में खुद बंद होने वाले टैग शामिल नहीं किए जाते हैं
  • डीओएम ट्री में एक अतिरिक्त नोड जोड़ता है, जिससे लेआउट से जुड़ी समस्याएं हो सकती हैं
  • इसे JavaScript के ज़रिए रजिस्टर किया जाना चाहिए

Lit ने पसंद के मुताबिक बनाए गए एलिमेंट सिस्टम के बजाय कस्टम एलिमेंट का इस्तेमाल किया है, क्योंकि ब्राउज़र में कस्टम एलिमेंट पहले से मौजूद होते हैं. Lit की टीम का मानना है कि क्रॉस-फ़्रेमवर्क से मिलने वाले फ़ायदों के मुकाबले, कॉम्पोनेंट ऐब्स्ट्रैक्ट लेयर से मिलने वाले फ़ायदे ज़्यादा होते हैं. असल में, Lit टीम ने JavaScript रजिस्ट्रेशन से जुड़ी मुख्य समस्याओं को दूर कर दिया है. इस टीम ने ऐसी समस्याओं को दूर किया है. इसके अलावा, GitHub जैसी कुछ कंपनियां, कस्टम एलिमेंट के लिए लेज़ी रजिस्ट्रेशन की सुविधा का इस्तेमाल करती हैं. इससे पेजों को बेहतर बनाने के लिए, अलग-अलग विकल्प का इस्तेमाल किया जाता है.

कस्टम एलिमेंट में डेटा भेजना

कस्टम एलिमेंट के बारे में एक आम गलतफ़हमी यह है कि डेटा को सिर्फ़ स्ट्रिंग के तौर पर पास किया जा सकता है. यह गलतफ़हमी इस बात से आ सकती है कि एलिमेंट के एट्रिब्यूट को सिर्फ़ स्ट्रिंग के तौर पर लिखा जा सकता है. हालांकि, यह सच है कि Lit, स्ट्रिंग एट्रिब्यूट को उनके तय किए गए टाइप में कास्ट करेगा, लेकिन कस्टम एलिमेंट, प्रॉपर्टी के तौर पर जटिल डेटा भी स्वीकार कर सकते हैं.

उदाहरण के लिए - नीचे दी गई LitElement की परिभाषा:

// 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>`;
  }
}

एक प्राइमिटिव रिएक्टिव प्रॉपर्टी num तय की गई है, जो किसी एट्रिब्यूट की स्ट्रिंग वैल्यू को number में बदल देगी. इसके बाद, attribute:false के साथ कॉम्प्लेक्स डेटा स्ट्रक्चर को पेश किया जाता है, जो Lit के एट्रिब्यूट को मैनेज करने की सुविधा को बंद कर देता है.

इस कस्टम एलिमेंट में डेटा पास करने का तरीका यहां बताया गया है:

<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>

राज्य और लाइफ़साइकल

अन्य रीऐक्ट लाइफ़साइकल कॉलबैक

static getDerivedStateFromProps

Lit में प्रॉप्स और स्टेट, दोनों एक ही क्लास प्रॉपर्टी नहीं हैं

shouldComponentUpdate

  • Lit में इसका बराबर shouldUpdate है
  • React के उलट, पहले रेंडर पर कॉल किया जाता है
  • रिऐक्ट के shouldComponentUpdate के फ़ंक्शन में मिलता-जुलता

getSnapshotBeforeUpdate

Lit में, getSnapshotBeforeUpdate, update और willUpdate, दोनों से मिलता-जुलता है

willUpdate

  • update से पहले कॉल किया गया
  • getSnapshotBeforeUpdate के उलट, render से पहले willUpdate को कॉल किया जाता है
  • willUpdate में रिएक्टिव प्रॉपर्टी में किए गए बदलाव, अपडेट साइकल को फिर से ट्रिगर नहीं करते
  • यह ऐसी प्रॉपर्टी वैल्यू को कैलकुलेट करने का बेहतरीन तरीका है जो अन्य प्रॉपर्टी पर निर्भर करती हैं. साथ ही, इनका इस्तेमाल अपडेट करने की बाकी प्रोसेस में किया जाता है
  • एसएसआर में, इस तरीके को सर्वर पर कॉल किया जाता है. इसलिए, यहां डीओएम को ऐक्सेस करने का सुझाव नहीं दिया जाता

update

  • willUpdate के बाद कॉल किया गया
  • getSnapshotBeforeUpdate के उलट, render से पहले update को कॉल किया जाता है
  • update में रिऐक्टिव प्रॉपर्टी में बदलाव करने पर, अपडेट साइकल फिर से ट्रिगर नहीं होता. ऐसा तब होता है, जब super.update को कॉल करने से पहले बदलाव किया गया हो
  • रेंडर किए गए आउटपुट को डीओएम में कमिट करने से पहले, कॉम्पोनेंट के आस-पास मौजूद डीओएम से जानकारी कैप्चर करने के लिए अच्छी जगह
  • एसएसआर में, इस तरीके को सर्वर पर नहीं बुलाया जाता

अन्य Lit Lifecycle कॉलबैक

ऐसे कई लाइफ़साइकल कॉलबैक हैं जिनके बारे में पिछले सेक्शन में नहीं बताया गया था, क्योंकि React में उनके लिए कोई ऐनालॉग नहीं है. कैंपेन के तीनों सब-टाइप के नाम ये रहे:

attributeChangedCallback

यह तब ट्रिगर होता है, जब एलिमेंट का कोई observedAttributes बदलता है. observedAttributes और attributeChangedCallback, दोनों कस्टम एलिमेंट स्पेसिफ़िकेशन का हिस्सा हैं. साथ ही, Lit एलिमेंट के लिए एट्रिब्यूट एपीआई उपलब्ध कराने के लिए, Lit ने इन एलिमेंट को लागू किया है.

adoptedCallback

यह तब ट्रिगर होता है, जब कॉम्पोनेंट को किसी नए दस्तावेज़ में ले जाया जाता है. उदाहरण के लिए, HTMLTemplateElement के documentFragment से मुख्य document में. यह कॉलबैक, कस्टम एलिमेंट की खास जानकारी का भी हिस्सा है. इसका इस्तेमाल सिर्फ़ उन ऐडवांस इस्तेमाल के उदाहरणों के लिए किया जाना चाहिए जिनमें कॉम्पोनेंट, दस्तावेज़ों में बदलाव करता है.

लाइफ़साइकल के अन्य तरीके और प्रॉपर्टी

ये तरीके और प्रॉपर्टी, क्लास के ऐसे सदस्य होते हैं जिन्हें कॉल किया जा सकता है, बदला जा सकता है या लाइफ़साइकल प्रोसेस में बदलाव करने में मदद मिलने का इंतज़ार किया जा सकता है.

updateComplete

यह एक ऐसा Promise है जो एलिमेंट के अपडेट होने के बाद पूरा हो जाता है, क्योंकि अपडेट और रेंडर लाइफ़साइकल असिंक्रोनस होते हैं. एक उदाहरण:

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

getUpdateComplete

यह एक ऐसा तरीका है जिसे updateComplete के ठीक होने पर, पसंद के मुताबिक बनाने के लिए ओवरराइड किया जाना चाहिए. यह आम तौर पर तब होता है, जब कोई कॉम्पोनेंट किसी चाइल्ड कॉम्पोनेंट को रेंडर कर रहा हो और उनके रेंडर साइकल सिंक होने चाहिए. उदाहरण के लिए,

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

performUpdate

यह तरीका, अपडेट लाइफ़साइकल कॉलबैक को कॉल करता है. आम तौर पर, इसकी ज़रूरत नहीं होती. हालांकि, कुछ मामलों में ऐसा करना ज़रूरी हो सकता है. जैसे, जब डेटा को एक साथ अपडेट करना हो या कस्टम शेड्यूलिंग के लिए.

hasUpdated

अगर कॉम्पोनेंट कम से कम एक बार अपडेट हुआ है, तो यह प्रॉपर्टी true होती है.

isConnected

कस्टम एलिमेंट के स्पेसिफ़िकेशन का हिस्सा, यह प्रॉपर्टी true होगी, अगर एलिमेंट फ़िलहाल मुख्य दस्तावेज़ ट्री से जुड़ा है.

Lit Update के लाइफ़साइकल का विज़ुअलाइज़ेशन

अपडेट के लाइफ़साइकल में तीन हिस्से होते हैं:

  • अपडेट से पहले
  • अपडेट करें
  • अपडेट के बाद

अपडेट से पहले

कॉलबैक के नामों वाले नोड का डायरेक्टेड ऐसाइक्लिक ग्राफ़. requestUpdate के लिए कन्स्ट्रक्टर. @property को प्रॉपर्टी सेटर में बदलें. attributeChangedCallback को प्रॉपर्टी सेटर में बदलें. प्रॉपर्टी सेटर को hasChanged. hasChanged to requestUpdate. requestUpdate, अगले लाइफ़साइकल ग्राफ़ को अपडेट करता है.

आपको requestUpdate के बाद, शेड्यूल किए गए अपडेट का इंतज़ार है.

अपडेट करें

कॉलबैक नामों के साथ नोड का एक निर्देशित असाइकिक ग्राफ़. अपडेट से पहले के लाइफ़साइकल की पिछली इमेज से ऐरो, performUpdate पर ले जाता है. performUpdate से shouldUpdate पर ले जाता है. shouldUpdate, ‘अगर गलत है, तो अपडेट पूरा करें’ और willUpdate, दोनों पर ले जाता है. willUpdate से update पर ले जाता है. update, रेंडर और अपडेट के बाद के लाइफ़साइकल के अगले ग्राफ़, दोनों पर ले जाता है. रेंडर, अपडेट के बाद के लाइफ़साइकल के अगले ग्राफ़ पर भी ले जाता है.

अपडेट के बाद

कॉलबैक के नामों वाले नोड का डायरेक्टेड ऐसाइक्लिक ग्राफ़. अपडेट लाइफ़साइकल पॉइंट की पिछली इमेज से firstUpdate पर ऐरो. firstअपडेट किया गया. अपडेट किया गया. अपडेट पूरा में अपडेट किया गया.

Hooks

हुक क्यों इस्तेमाल करें

React में हुक की सुविधा, फ़ंक्शन कॉम्पोनेंट के ऐसे इस्तेमाल के उदाहरणों के लिए शुरू की गई थी जिनमें स्टेटस की ज़रूरत होती है. कई आसान मामलों में, हुक वाले फ़ंक्शन कॉम्पोनेंट, क्लास कॉम्पोनेंट के मुकाबले ज़्यादा आसान और पढ़ने में आसान होते हैं. हालांकि, एसिंक्रोनस स्टेट अपडेट शुरू करते समय और हुक या इफ़ेक्ट के बीच डेटा पास करते समय, हुक पैटर्न काफ़ी नहीं होते. हालांकि, रिऐक्टिव कंट्रोलर जैसे क्लास-आधारित समाधान ज़्यादा कारगर साबित होते हैं.

एपीआई अनुरोध हुक और कंट्रोलर

एक हुक लिखना आम बात है, जो एपीआई से डेटा का अनुरोध करता है. उदाहरण के लिए, रिऐक्ट फ़ंक्शन का यह कॉम्पोनेंट लें, जो ये काम करता है:

  • index.tsx
    • टेक्स्ट रेंडर करता है
    • useAPI के प्रतिसाद
        को रेंडर करता है
      • यूज़र आईडी + उपयोगकर्ता का नाम
      • त्रुटि संदेश
        • 11वें उपयोगकर्ता तक पहुंचने पर 404 कोड दिखना (डिज़ाइन के हिसाब से)
        • अगर एपीआई फ़ेच को रोका जाता है, तो गड़बड़ी को रोकें
      • लोडिंग संदेश
    • यह एक कार्रवाई बटन रेंडर करता है
      • अगला उपयोगकर्ता: यह अगले उपयोगकर्ता के लिए एपीआई फ़ेच करता है
      • रद्द करें: इससे एपीआई को फ़ेच करने की प्रोसेस रद्द होती है और गड़बड़ी दिखती है
  • useApi.tsx
    • यह नीति, useApi कस्टम हुक के बारे में बताती है
    • यह किसी एपीआई से उपयोगकर्ता ऑब्जेक्ट को असाइन किए बिना फ़ेच करेगा
    • उत्सर्जन:
      • उपयोगकर्ता नाम
      • फ़ेच करने की प्रोसेस लोड हो रही है या नहीं
      • गड़बड़ी का कोई मैसेज
      • फ़ेच को रोकने के लिए कॉलबैक
    • अलग किए जाने पर, फ़ेच करने की प्रोसेस जारी है

यहां Lit + रिऐक्टिव कंट्रोलर लागू करने का तरीका बताया गया है.

सीखने वाली अहम बातें:

  • रिऐक्टिव कंट्रोलर, कस्टम हुक की तरह ही होते हैं
  • कॉलबैक और इफ़ेक्ट के बीच ऐसा डेटा पास करना जिसे रेंडर नहीं किया जा सकता
    • React, useRef का इस्तेमाल करके useEffect से useCallback के बीच डेटा पास करता है
    • Lit एक प्राइवेट क्लास प्रॉपर्टी का इस्तेमाल करता है
    • React, निजी क्लास प्रॉपर्टी के व्यवहार की नकल करता है

इसके अलावा, अगर आपको हुक के साथ React फ़ंक्शन कॉम्पोनेंट सिंटैक्स पसंद है, लेकिन Lit में बिना बिल्ड वाला माहौल है, तो Lit की टीम आपको Haunted लाइब्रेरी इस्तेमाल करने का सुझाव देती है.

बच्चे

डिफ़ॉल्ट स्लॉट

जब एचटीएमएल एलिमेंट को slot एट्रिब्यूट नहीं दिया जाता है, तो उन्हें बिना नाम वाले डिफ़ॉल्ट स्लॉट में असाइन कर दिया जाता है. नीचे दिए गए उदाहरण में, MyApp एक पैराग्राफ़ को नाम वाले स्लॉट में स्लॉट करेगा. दूसरा पैराग्राफ़, डिफ़ॉल्ट रूप से बिना नाम वाले स्लॉट में दिखेगा".

@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>
   `;
  }
}

स्लॉट से जुड़े अपडेट

स्लॉट के वंशजों का स्ट्रक्चर बदलने पर, slotchange इवेंट ट्रिगर होता है. लिटिल कॉम्पोनेंट, इवेंट सुनने वाले व्यक्ति को slotchange इवेंट से बाइंड कर सकता है. नीचे दिए गए उदाहरण में, shadowRoot में मिला पहला स्लॉट, slotchange पर कंसोल में assignedNodes के तौर पर लॉग किया जाएगा.

@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>
   `;
  }
}

रेफ़रंस

रेफ़रंस जनरेशन

Lit और React, दोनों अपने render फ़ंक्शन के कॉल होने के बाद, HTMLElement का रेफ़रंस दिखाते हैं. हालांकि, यह जानना ज़रूरी है कि React और Lit, डीओएम को कैसे बनाते हैं. इसे बाद में, Lit @query डेकोरेटर या React रेफ़रंस के ज़रिए दिखाया जाता है.

React एक फ़ंक्शनल पाइपलाइन है, जो HTMLElements के बजाय React कॉम्पोनेंट बनाता है. HTMLElement को रेंडर होने से पहले ही Ref का एलान किया जाता है, इसलिए मेमोरी में एक स्पेस तय होता है. इसलिए, आपको रेफ़रंस की शुरुआती वैल्यू के तौर पर null दिखता है, क्योंकि असल DOM एलिमेंट अभी तक नहीं बनाया गया है या रेंडर नहीं किया गया है, यानी useRef(null).

जब ReactDOM किसी प्रतिक्रिया वाले कॉम्पोनेंट को HTMLElement में बदल देता है, तब यह Reactcomponent में ref नाम का एट्रिब्यूट खोजता है. अगर उपलब्ध हो, तो ReactDOM, HTMLElement का रेफ़रंस ref.current पर डालता है.

LitElement, हुड के तहत टेंप्लेट एलिमेंट बनाने के लिए, lit-html से html टेंप्लेट टैग फ़ंक्शन का इस्तेमाल करता है. LitElement, टेंप्लेट के कॉन्टेंट को रेंडर करने के बाद, कस्टम एलिमेंट के शैडो डीओएम में स्टैंप करता है. शैडो डीओएम, स्कोप वाला डीओएम ट्री है, जिसे शैडो रूट के ज़रिए एनकैप्सुलेट करता है. इसके बाद, @query डेकोरेटर प्रॉपर्टी के लिए एक गेट्टर बनाता है, जो स्कोप वाले रूट पर this.shadowRoot.querySelector करता है.

एक से ज़्यादा एलिमेंट पर क्वेरी करना

नीचे दिए गए उदाहरण में, @queryAll डेकोरेटर, शैडो रूट में मौजूद दो पैराग्राफ़ को NodeList के तौर पर दिखाएगा.

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

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

असल में, @queryAll, paragraphs के लिए एक गैटर बनाता है, जो this.shadowRoot.querySelectorAll() के नतीजे दिखाता है. JavaScript में, एक ही काम करने के लिए, गटर का एलान किया जा सकता है:

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

क्वेरी में बदलाव करने वाले एलिमेंट

@queryAsync डेकोरेटर ऐसे नोड को हैंडल करने के लिए बेहतर विकल्प है जो किसी अन्य एलिमेंट प्रॉपर्टी की स्थिति के आधार पर बदल सकता है.

नीचे दिए गए उदाहरण में, @queryAsync को पहले पैराग्राफ़ एलिमेंट मिलेगा. हालांकि, पैराग्राफ़ एलिमेंट सिर्फ़ तब रेंडर किया जाएगा, जब renderParagraph बिना किसी क्रम के कोई विषम संख्या जनरेट करेगा. @queryAsync डायरेक्टिव, एक प्रॉमिस दिखाएगा. यह प्रॉमिस तब रिज़ॉल्व होगा, जब पहला पैराग्राफ़ उपलब्ध होगा.

@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()}
   `;
  }
}

मध्यस्थता करने वाली राज्य

React में, कॉलबैक का इस्तेमाल किया जाता है, क्योंकि स्थिति की मध्यस्थता React खुद करती है. React, एलिमेंट से मिलने वाली स्थिति पर भरोसा न करने की पूरी कोशिश करता है. डीओएम, रेंडरिंग प्रोसेस का सिर्फ़ एक असर है.

बाहरी स्थिति

Lit के साथ Redux, MobX या स्टेट मैनेजमेंट की किसी भी अन्य लाइब्रेरी का इस्तेमाल किया जा सकता है.

लिटिल कॉम्पोनेंट, ब्राउज़र के स्कोप में बनाए जाते हैं. इसलिए, ऐसी लाइब्रेरी जो ब्राउज़र के दायरे में भी मौजूद है वह Lit में उपलब्ध है. लिटिल में मौजूदा स्टेट मैनेजमेंट सिस्टम का इस्तेमाल करने के लिए, कई शानदार लाइब्रेरी बनाई गई हैं.

यहां Vaadin की एक सीरीज़ दी गई है, जिसमें Lit कॉम्पोनेंट में Redux का फ़ायदा पाने का तरीका बताया गया है.

Adobe के lit-mobx पर नज़र डालें और जानें कि बड़े पैमाने पर काम करने वाली साइट, Lit में MobX का फ़ायदा कैसे ले सकती है.

साथ ही, Apollo Elements देखें और जानें कि डेवलपर अपने वेब कॉम्पोनेंट में GraphQL को कैसे शामिल कर रहे हैं.

Lit, ब्राउज़र की नेटिव सुविधाओं के साथ काम करता है. साथ ही, ब्राउज़र के दायरे में स्टेटस मैनेजमेंट के ज़्यादातर समाधानों का इस्तेमाल, Lit कॉम्पोनेंट में किया जा सकता है.

शैलीकृत करना

शैडो डीओएम

किसी कस्टम एलिमेंट में स्टाइल और डीओएम को नेटिव तौर पर इनकैप्सुलेट करने के लिए, Lit Shadow DOM का इस्तेमाल करता है. शैडो रूट, मुख्य दस्तावेज़ ट्री से अलग एक शैडो ट्री जनरेट करते हैं. इसका मतलब है कि ज़्यादातर स्टाइल इस दस्तावेज़ के दायरे में आते हैं. हालांकि, कुछ स्टाइल लीक हो जाते हैं. जैसे, रंग और फ़ॉन्ट से जुड़े अन्य स्टाइल.

शैडो डीओएम, सीएसएस की खास बातों में नए कॉन्सेप्ट और सिलेक्टर को भी शामिल करता है:

: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.
   */
}

स्टाइल शेयर करना

Lit की मदद से, css टेंप्लेट टैग के ज़रिए CSSTemplateResults के तौर पर, कॉम्पोनेंट के बीच स्टाइल आसानी से शेयर की जा सकती हैं. उदाहरण के लिए:

// 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>`
  }
}

थीम बनाई जा रही है

शैडो रूट, पारंपरिक थीमिंग के लिए थोड़ी चुनौती पेश करते हैं. आम तौर पर, ये टॉप-डाउन स्टाइल टैग के तरीके होते हैं. शैडो डीओएम का इस्तेमाल करने वाले वेब कॉम्पोनेंट के साथ थीमिंग को मैनेज करने का पारंपरिक तरीका, सीएसएस कस्टम प्रॉपर्टी के ज़रिए स्टाइल एपीआई को एक्सपोज़ करना है. उदाहरण के लिए, Material Design के ज़रिए इस पैटर्न का इस्तेमाल किया जाता है:

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

इसके बाद, उपयोगकर्ता कस्टम प्रॉपर्टी वैल्यू लागू करके साइट की थीम बदल सकता है:

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

अगर आपको टॉप-डाउन थीमिंग की ज़रूरत है और स्टाइल एक्सपोज़ नहीं की जा सकतीं, तो createRenderRoot को बदलकर this करके, शैडो डीओएम को हमेशा बंद किया जा सकता है. इसके बाद, आपके कॉम्पोनेंट के टेंप्लेट को कस्टम एलिमेंट में रेंडर किया जाएगा, न कि कस्टम एलिमेंट से जुड़े शैडो रूट में. इसके बाद, ये चीज़ें मिट जाएंगी: स्टाइल एनकैप्सुलेशन, डीओएम एनकैप्सुलेशन, और स्लॉट.

प्रोडक्शन

IE 11

अगर आपको IE 11 जैसे पुराने ब्राउज़र के लिए सहायता चाहिए, तो आपको कुछ पॉलीफ़िल लोड करने होंगे, जो करीब 33 केबी के हो जाते हैं. इस बारे में ज़्यादा जानकारी यहां मिल सकती है.

शर्तों के हिसाब से बंडल

Lit टीम का सुझाव है कि दो अलग-अलग बंडल उपलब्ध कराएं. एक IE 11 के लिए और दूसरा आधुनिक ब्राउज़र के लिए. ऐसा करने के कई फ़ायदे हैं:

  • ES 6 में तेज़ी से काम किया जा सकता है और यह आपके ज़्यादातर क्लाइंट को सेवा देगा
  • ट्रांसमिट किया गया ES 5, बंडल का साइज़ काफ़ी बढ़ा देता है
  • शर्त वाले बंडल आपको दोनों का सर्वश्रेष्ठ देते हैं
    • IE 11 के लिए सहायता
    • मॉडर्न ब्राउज़र पर काम करने में कोई रुकावट नहीं आती

शर्तों के हिसाब से दिखाए जाने वाले बंडल बनाने के तरीके के बारे में ज़्यादा जानकारी के लिए, यहां हमारी दस्तावेज़ साइट पर जाएं.