LitElement 속성: @property vs@internalProperty

10877 단어 litelementtypescript
LitElement는 경량급 웹 응용 프로그램을 구축하는 가장 좋은 선택이다. 웹 구성 요소 표준을 바탕으로 하고 TypeScript의 도움으로 우리는 더 많은 가능성을 볼 수 있으며 더 좋은 개발자가 웹 구성 요소를 더욱 빨리 구축하는 것을 체험할 수 있기 때문이다.
본고에서 나는 TypeScript를 사용하여 실현된 @property@internalProperty 장식기의 실제 사용을 설명할 것이다.

문제.


사용자 목록을 표시할 작은 프로그램을 만들고 있다고 가정하십시오.그 중 하나를 선택하면 다른 세부 정보를 표시해야 합니다.이 경우 주소 정보입니다.

다음은 LitElement을 사용하여 웹 구성 요소를 실현하기 전에 데이터 모델과 데이터 집합을 정의합니다.

데이터 모델링과 데이터 집합


데이터 모델


TypeScript 인터페이스와 정적 유형을 사용하여 모델을 준비합니다.
// model.ts
export interface User {
  id: number;
  name: string;
}

export interface Address {
  country: string;
  state: string;
  city: string;
  street: string;
  zipCode: number;
}
Address 인터페이스에 전체 주소를 나타내는 속성 세트가 표시됩니다.

데이터의 출처


테스트를 더욱 쉽게 하기 위해서, 이전 모델과 일치하는 실체 데이터 집합을 만듭니다.
// data.ts
import { Address } from "./model";
import { User } from "./model";

export const users: User[] = [
  {
    id: 0,
    name: "Donald Mayfield"
  },
  {
    id: 1,
    name: "Jill J. Fritz"
  },
  {
    id: 2,
    name: "Terry Buttram"
  }
];

export const address: Address[] = [
  {
    street: "2180 BELLFLOWER",
    country: "USA",
    state: "AL",
    city: "Madison",
    zipCode: 35064
  },
  {
    street: "845 ODOM ROAD, SUITE 200",
    country: "USA",
    state: "CA",
    city: "Los Angeles",
    zipCode: 90720
  },
  {
    street: "9025 QUEENS BLVD",
    country: "USA",
    state: "NY",
    city: "Queens",
    zipCode: 11355
  }
];
usersaddress 사이의 관계는 매우 간단하다. 사용자idaddress 수조의 위치가 일치한다.

LitElement 속성 사용


LitElement은 다양한 방법으로 속성을 관리할 수 있습니다.파일에서 설명한 대로

LitElement manages your declared properties and their corresponding attributes.


이것은 정적 properties 필드나 장식기를 사용하여 완성할 수 있습니다.decorators의 강력한 기능을 사용하여 TypeScript를 사용하겠습니다.
다음 부분을 통해 우리는 실천에서 부동산 관리를 더욱 잘 이해할 것이다.

MainViewer 컨테이너 만들기


첫 번째 구성 요소를 포함하는 클래스를 만듭니다.이 예에서, 우리는 용기 구성 요소를 정의할 것입니다. 이 구성 요소는 사용자 목록과 상세한 정보를 표시할 것입니다.
import {
  LitElement,
  html,
  customElement,
  css,
  internalProperty
} from "lit-element";
import { users } from "./data";
import { User } from "./model";

@customElement("main-viewer")
class MainViewer extends LitElement {
  static styles = css`
    :host {
      display: block;
    }
  `;

  users: User[] = [];
  userId?: number;

  constructor() {
    super();
  }

  render() {
    return html`
      <div>
        <h1>User Address Viewer</h1>
        <span>Select a User to see the Address:</span>
        <ul>
          ${this.users.map(
            user => html`
              <li>
                <a href="#" @click="${() => this.viewAddress(user.id)}"
                  >${user.name}</a
                >
              </li>
            `
          )}
        </ul>
      </div>
    `;
  }

  async connectedCallback() {
    super.connectedCallback();
    this.users = await this.getUsers();
  }

  private getUsers() {
    // in the real-world you'll get the data from a service, file, etc.
    return new Promise<User[]>((resolve, reject) => resolve(users));
  }

  private viewAddress(id: number) {
    this.userId = id;
  }
}
지금까지 이 구성 요소에서 어떤 일이 일어났는지 설명합니다.
  • (static styles 속성은 태그의 템플릿 문자(css를 사용하여 어셈블리의 스타일을 정의합니다.
  • 기본 목록에 표시할 사용자 집합을 저장하는 데 사용되는 두 가지 클래스 속성을 정의합니다. users또한 userId에는 선택한 사용자 식별자에 대한 참조가 포함됩니다(다른 사용자를 선택할 때마다 값이 변경됩니다).
  • (render 방법은 템플릿 텍스트 (html 를 통해 HTML 내용을 되돌려줍니다.구성 요소 속성이 바뀌면 이 함수를 호출합니다.
  • (connectedCallback 함수 호출getUsers은 구성 요소를 문서의 DOM에 추가할 때 초기 데이터를 얻을 수 있도록 합니다.
  • (getUsers 함수는 비동기 호출(현실 장면에서)을 실행하여 데이터를 검색해야 한다.
  • 사용자가 링크에서 클릭 동작을 실행하면 viewAddress 함수는 선택한 대상의 id을 수신합니다.그런 다음 클래스 속성userId이 업데이트됩니다.
  • 앞에 코드가 아주 좋아요.하지만 아직 아무런 데이터도 표시되지 않습니다!우리는 페이지에서 제목과 공백 부분만 볼 수 있고, 나타나는 사용자 목록은 볼 수 없습니다.

    @internalProperty 장식기 사용하기


    이 문제를 해결하기 위해서 웹 구성 요소의 업데이트 주기를 확보해야 합니다.
    업데이트 주기를 언제 실행해야 할지 생각해 보세요: 목록이 바뀔 때마다!단, 이것은 클래스의 변수나 속성을 업데이트할 때마다 완성할 수 없습니다.대신 렌더링 작업을 수행하거나 어셈블리 업데이트를 유지하는 키 속성을 언급해야 합니다.이러한 주요 속성에 대해 LitElement 속성을 호출합니다.
    이러한 속성이 확인되면 속성으로 선언해야 합니다.
    // main-viewer.ts
    
    @customElement("main-viewer")
    class MainViewer extends LitElement {
      // ...
    
      @internalProperty() users: User[] = [];
      @internalProperty() userId?: number;
    
      constructor() {
        super();
      }
    
      // ...
    }
    
    왜 이런 상황에서 사용합니까users?
  • @internalProperty 구성 요소에 대해 구성 요소 외부에서 인용MainViewer하거나 users할 필요가 없습니다.
  • 위에서 볼 때 우리는 userIdusers 속성을 사유 또는 보호받는 것으로 볼 수 있다.
  • 다시 말하면 LitElement은 이러한 속성 변경을 관찰하고 반응하여 템플릿을 자동으로 렌더링/업데이트합니다.

    @property Decorator 사용


    AddressViewer 구성 요소 만들기


    서브어셈블리를 생성하기 전에 컨테이너에서 사용하는 방법을 생각해 보겠습니다.웹 구성 요소의 경우 다음과 같은 요소와 속성이 필요하다고 가정합니다.
    <address-viewer .userId=${userId}></address-viewer>
    
    이것은 새 userId 구성 요소가 해당하는 주소를 검색하려면 수신 address-viewer 값이 필요하다는 것을 의미한다.userId 기호는 단방향 데이터 귀속을 속성에 적용한다. 이것은 .userId=${userId} 구성 요소가 AddressViewer를 공공 속성으로 하는 것을 의미한다.

    @속성 vs@internalProperty decorators


    앞의 사항을 고려하여 새 파일을 만듭니다userId.
    import {
      LitElement,
      html,
      property,
      customElement,
      css,
      internalProperty
    } from "lit-element";
    import { address } from "./data";
    import { Address } from "./model";
    
    @customElement("address-viewer")
    class AddressViewer extends LitElement {
      static styles = css`
        :host {
          display: block;
        }
    
        table {
          border-collapse: collapse;
          width: 100%;
        }
    
        td,
        th {
          border: 1px solid gray;
          text-align: left;
          padding: 5px;
        }
      `;
    
      @property({ type: Number }) userId: number;
      @internalProperty() userAddress?: Address;
    
      constructor() {
        super();
      }
    
      render() {
        if (this.userAddress === undefined) {
          return html``;
        }
    
        return html`
          <table>
            <tr>
              <th>Country</th>
              <th>State</th>
              <th>City</th>
              <th>Street</th>
              <th>Zip Code</th>
            </tr>
            <tr>
              <td>${this.userAddress.country}</td>
              <td>${this.userAddress.state}</td>
              <td>${this.userAddress.city}</td>
              <td>${this.userAddress.street}</td>
              <td>${this.userAddress.zipCode}</td>
            </tr>
          </table>
        `;
      }
    
      update(changedProperties: Map<string, unknown>) {
        if (changedProperties.has("userId")) {
          const oldValue = changedProperties.get("userId") as number;
          console.log("userId updated, newVal", this.userId, "oldVal", oldValue);
          this.loadAddress(this.userId);
        }
        super.update(changedProperties);
      }
    
      private async loadAddress(id: number) {
        this.userAddress = await this.getAddress(id);
      }
    
      private getAddress(id: number) {
        return new Promise<Address>((resolve, reject) => resolve(address[id]));
      }
    }
    
    다시 한 번 앞의 소스 코드를 살펴보겠습니다.

    - 주소 뷰어ts 속성은 userId decorator를 사용하는 구성 요소의 공통 속성으로 정의됩니다.

    @property 속성은 구성 요소의 공공 속성이 필요하지 않습니다.반대로, 이것은 userAddress decorator를 사용하여 정의한 것으로, 변경되면 업데이트 주기를 촉발합니다.

    - 처음에는 @internalProperty

    undefined 메서드는 속성을 변경할 때마다 표시할 HTML 내용을 반환합니다.

    - 참고: 함수는 필수 객체가 포함된 렌더링에만 의미 있는 템플릿을 반환합니다.

    userAddress 함수는 속성 값을 반영하고 update 함수를 호출한다.
  • 변경된 속성이 있는 render을 받았습니다.
  • 속성이 변경되었는지 확인하고 Map에 대한 호출을 실행합니다.
  • 이 방법을 언제 다시 쓰든지 간에 userId를 호출해서 템플릿을 보여야 한다.
  • loadAddress 함수에서 super.update()의 새 값을 가져오고 유틸리티 함수를 호출하여Address 대상을 검색합니다.
  • loadAddress 구성 요소가 준비되어 있습니다. 메인 용기의 하위 구성 요소로 사용해야 합니다.다음과 같이 userId 함수를 업데이트합니다.
    // main-viewer.ts
    
    // Let's import the <address-viewer> definition
    import "./address-viewer";
    
    @customElement("main-viewer")
    class MainViewer extends LitElement {
      //...
    
      render() {
        return html`
          <div>
            <h1>User Address Viewer</h1>
            <span>Select a User to see the Address:</span>
            <ul>
              ${this.users.map(
                user => html`
                  <li>
                    <a href="#" @click="${() => this.viewAddress(user.id)}"
                      >${user.name}</a
                    >
                  </li>
                `
              )}
            </ul>
            <address-viewer .userId=${this.userId}></address-viewer>
          </div>
        `;
      }
    
     // ... 
    }
    
    마찬가지로 단방향 데이터 귀속 AddressViewer 을 주의하십시오. render 구성 요소가 변경될 때 .userId=${this.userId} 구성 요소의 렌더링 동작을 터치합니다.이게 마법이야, 그렇지?

    현장 프레젠테이션


    이 코드 한번 해볼래요?Stackblitz 편집기를 열려면 다음과 같이 하십시오.
    문제가 있으면 언제든지 연락 주세요.계속해서 저GitHub를 주목해 주시고 제 일에 대한 더 많은 정보를 얻으세요.
    현대 인터넷 컨설팅 회사로 기업의 디지털화 전환을 돕는 데 주력하고 있다.React, Angular, Vue, 웹 구성 요소,GraphQL,Node,Bazel 또는 Polymer에 대한 전문가 구조 지도, 교육 또는 문의는 방문thisdotlabs.com하십시오.
    이런 인터넷 매체는 모든 사람을 위해 포용성과 교육적인 네트워크를 만드는 데 전념한다.이벤트, 팟캐스트, 무료 콘텐츠를 통해 현대 인터넷의 최신 진전을 알 수 있습니다.자세한 내용은 thisdot.co를 참조하십시오.

    좋은 웹페이지 즐겨찾기