(번역) React, Angular, Vue, Svelte에서 리스트를 렌더링하는 방법

강엽이·2022년 5월 23일
22
post-thumbnail

React, Angular, Vue, Svelte에서 리스트를 렌더링하는 방법

어떤 접근 방식이 가장 좋습니까?

원문 : https://javascript.plainenglish.io/rendering-a-list-in-react-angular-vue-and-svelte-a2ea987f0c21

이 글에서는 가장 많이 사용되는 4가지 프레임워크(React, Angular, Vue, Svelte)를 비교하여 리스트 렌더링에 대한 접근 방식을 분석합니다. 유사한 점과 특별한 점을 보여주기 위해 각 프레임워크에 대한 플레이그라운드가 있는 코드 예제를 제공합니다. 마지막으로 각 솔루션에 대한 제 개인적인 의견을 추가하겠습니다. 가장 좋아하는 접근 방식은 무엇인지 편하게 댓글 남겨주세요😊

면책 조항: React가 프레임워크가 아닌 라이브러리라는 것을 알 고 있지만 이 글의 목적을 위해 프레임워크라고 부를 것입니다.

소개

프로그래밍 언어 하나를 아주 잘 안다면 다른 언어를 배우는 것은 간단하다는 말을 들어본 적이 있을 것 입니다. 많은 프로그래밍 구조(루프, 조건부, 배열, 함수, 클래스)가 다양한 언어에서 동일한 방식으로 사용되므로 문법만 익힌다면 좋은 시작을 할 수 있습니다. 만약 여러분이 프런트엔드 웹 개발자라면 프런트엔드 프레임워크도 동일하다는 것을 깨달았을 것입니다. 주요 개념은 항상 동일합니다. 엘리먼트 목록을 렌더링, 조건부로 엘리먼트를 렌더링, 프로퍼티 전달, 상태 관리, 라이프 사이클 이벤트 등 다른 많은 컨셉들의 솔루션이 항상 있습니다.

이 예제에서는 리스트를 매우 단순화합니다. namelogo 속성(attribute)를 포함하는 객체 배열을 반복합니다. 정렬된 리스트에 데이터를 표시하고 항목의 현재 인덱스를 표시합니다. 다음 코드는 우리가 보여주고자 하는 아이템 배열입니다.

interface Framework {
    name: string;
    logo: string;
}
  
const items: Framework[] = [
    {
      name: 'React',
      logo: 'https://react-logo.png',
    },
    // ... Angular, Vue, Svelte
  ];

React

자바스크립트에 익숙하다면 가정하면 React가 리스트를 렌더링하는 방식은 매우 간단할 것입니다. React를 사용하면 map() 함수를 사용하여 배열을 쉽게 반복할 수 있습니다. 아래에서 아이템 배열을 반복해서 각 아이템의 <li> 엘리먼트를 반환합니다. map()함수의 두 번째 매개변수를 사용할 수 있기 때문에 현재 인덱스에 접근하는 것도 쉽습니다. 엘리먼트 내에서 중괄호 {}item 프로퍼티를 래핑하여 포함할 수 있습니다. 또한, 리스트에서 엘리먼트를 동적으로 제거하거나 추가하려는 경우 좋은 성능을 보장하기 위해 고유 key 속성을 추가하고 있습니다. 이 속성에 대해서 더 자세히 살펴 보겠습니다.

<ol>
  {items.map(({ name, logo }, index) => (
    <li key={`${name}-${index}`}>
      <span>{index + 1}.</span>
      <img className="logo" src={logo} />
      <span>{name}</span>
    </li>
  ))}
</ol>

Stackblitz에서 예제를 체험해 볼 수 있습니다.

특이사항

React가 다른 프레임워크와 다른 점과 React 내에서 리스트를 사용할 때 고려해야 할 사항을 살펴보겠습니다.

Key 속성

React에서는 리스트가 동적으로 변경될 수 있는 경우 각 항목에 key 속성을 전달해야 합니다. 배열 내의 키는 엘리먼트 간에 고유해야 합니다. 그렇지 않으면 React에서 오류가 발생합니다. 하지만 전역적으로 고유할 필요는 없습니다. 모든 프레임워크에서 고유 키를 제공하는 개념을 살펴보겠지만 지금 그 개념에 대해 자세히 설명하겠습니다. 키 속성의 주요 아이디어는 다른 모든 프레임워크에서도 적용됩니다.

키는 전역적으로 고유하지 않아도 되고, 형제간에만 고유해야 합니다. - reactjs.org

key 속성은 React에 대한 힌트 역할만 할 뿐 컴포넌트에 전달되지는 않습니다. 이 말은 우리의 예제에서 전달된 키가 DOM에 표시되지 않는다는 것을 의미합니다. 컴포넌트에 동일한 값이 필요한 경우 다른 이름을 가진 prop으로 명시적으로 전달합니다.

각 엘리먼트에 고유한 키를 어떻게 할당할까요? 표시하는 엘리먼트에 이미 고유한 ID가 있을 수 있으므로 키는 데이터에서 가져올 수 있습니다. 현재 인덱스를 key 속성으로 전달할 수도 있지만 만약 항목 순서가 변경될 수 있는 경우 React는 그렇게 하지 않을 것을 권장합니다. React는 최신 트리와 일치하도록 효율적으로 UI를 업데이트하는 방법을 파악해야 하므로 성능에 부정적인 영향을 미칠 수 있습니다.

최후의 수단으로 배열 항목의 인덱스를 키로 전달할 수 있습니다. 항목이 재정렬되지 않은 경우 잘 작동할 수 있지만 재정렬이 느릴 것입니다. - reactjs.org

저는 정기적으로 엘리먼트의 현재 인덱스를 해당 값과 결합합니다. 이렇게 하면 키가 중복되지 않고 React의 성능에 영향을 미치는 것을 방지할 수 있습니다.

개인적인 의견

저는 React가 리스트 렌더링을 처리하는 방식을 좋아합니다. 새로운 문법을 이해할 필요가 없기 때문에 기본 자바스크립트를 사용하는 것이 자연스럽습니다. 자바스크립트/타입스크립트, Web Components, Lit library를 많이 다루다 보니 React를 처음 접했을 때 새로운 것을 배울 필요가 없다고 느꼈습니다.

Angular

Angular에서는 *ngFor 지시문을 사용하여 리스트를 렌더링 합니다. let 키워드를 사용하여 item이라는 루프 변수를 정의합니다. 그런 다음 보간 {{}}을 사용하여 템플릿 내부의 객체 속성에 접근할 수 있습니다. 또한, 로컬 변수를 사용하여 현재 인덱스에 접근하고 React의 키 속성과 비슷한 솔루션인 trackBy 함수를 제공합니다. 템플릿은 다음과 같습니다.

<ol>
  <li *ngFor="let item of items; index as i; trackBy: trackItem">
    <span>{{ i + 1 }}.</span>
    <img class="logo" [src]="item.logo" />
    <span>{{ item.name }}</span>
  </li>
</ol>

Stackblitz에서 예제를 체험해 볼 수 있습니다.

특이사항

Angular가 다른 프레임워크와 다른 점과 Angular 내에서 리스트를 사용할 때 고려해야 할 사항을 살펴보겠습니다.

TrackBy 함수

trackBy 함수는 React의 key 속성과 같은 역할을 합니다. 이를 통해 각 반복 가능한 엘리먼트에 대해 고유한 식별자를 반환하는 함수를 정의할 수 있습니다.

만약 커스텀 [TrackByFunction](https://angular.io/api/core/TrackByFunction)이 제공되지 않으면, [NgForOf](https://angular.io/api/common/NgForOf)객체 ID(object identity)를 키로 사용합니다. - https://angular.io/api/common/NgForOf

만약 사용자 정의의 TrackByFunction을 전달하지 않고 리스트의 데이터가 변경되면 Angular는 변경되는 특정 객체를 식별할 수 없습니다. 모든 참조가 수정되기 때문에 전체 리스트가 다시 렌더링됩니다. 따라서 모든 객체는 angular에게 새로운 것처럼 보입니다.

trackBy 함수는 인덱스와 현재 엘리먼트를 인수로 사용하고 해당 엘리먼트의 고유 식별자를 반환합니다. 다음은 사용자 정의의 trackBy 함수 예제 입니다.

trackItem(index: number, item: Framework) {
  return `${item.name}-${index}`;
}

지역 변수

Angular의 *ngFor 지시문은 지역 변수에 별칭을 지정할 수 있는 일부 값을 내보냅니다. 예를 들어 다음과 같습니다.

*ngFor="let item of items; index as i, first as isFirst"

변수 isFirst를 템플릿 내에서 사용할 수 있으며 항목이 반복 가능한 값의 첫 번째 항목일 때 true를 확인합니다.

다음 값들을 지역 변수에 별칭으로 지정할 수 있습니다.

  • $implicit: T: 반복 가능한 값에 있는 개별 항목의 값 ([ngForOf](https://angular.io/api/common/NgForOf)).
  • ngForOf: NgIterable<T>: 반복 가능한 표현식의 값.
  • index: numbe: 반복 가능한 값에서 현재 항목의 인덱스.
  • count: number: 반복 가능한 값의 길이.
  • first: boolean: 항목이 반복 가능한 값에서 첫 번째 항목일 경우 True.
  • last: boolean: 항목이 반복 가능한 값에서 마지막 항목일 경우 True.
  • even: boolean: 항목이 반복 가능한 값에서 짝수 번째 항목일 경우 True.
  • odd: boolean: 항목이 반복 가능한 값에서 홀수 번째 항목일 경우 True.

파이프(Pipes)

Angular의 파이프는 입력 값을 받아들이고 변환된 값을 반환하는 템플릿 표현식의 간단한 함수입니다. 파이프를 사용하여 문자열, 통화 금액, 날짜를 변환하고 아이템 배열을 정렬할 수 있습니다. 많은 내장 파이프들이 있습니다. 예를 들어, 가장 중요한 것 중 하나는 AsyncPipe로, 템플릿에서 직접 promises와 observables를 사용할 수 있습니다.

이 예제에서는 Angular의 파이프를 사용하지는 않지만 배열을 변환하는 좋은 방법입니다. 문자 'S'로 시작하는 모든 항목을 필터링하는 파이프를 만들어 보겠습니다.

@Pipe({ name: 'filterStartingWithS' })
export class FilterStartsWithSPipe implements PipeTransform {
  transform(items: Framework[]) {
    return items.filter((item) => item.name.startsWith('S'));
  }
}

템플릿에 활용해 보겠습니다.

<ol>
  <li
    *ngFor="
    let item of items | filterStartingWithS;
    index as i;
    trackBy: trackItem
    "
  >
    <span>{{ i + 1 }}.</span>
    <img class="logo" [src]="item.logo" />
    <span>{{ item.name }}</span>
  </li>
</ol>

그러면 Svelte 항목만 표시됩니다.

개인적인 의견

저는 프레임워크의 새로운 문법을 배워야 하는 것을 좋아하지 않습니다. 다른 사람들 모두 그렇지는 않지만 저는 몇 년 동안 Angular로 작업했음에도 처음 본능적으로 ngFor 문법을 사용해서 틀린적이 있습니다. 왜냐하면 *를 앞에 넣는 것을 잊어 버렸기 때문입니다.

그 외에도 Angular의 솔루션은 깔끔하고 우아합니다. 특별한 지역 변수를 포함할 수 있는 것이 유용합니다. 그러나 index 만을 사용하여 대부분을 쉽게 재현할 수 있으므로 지역 변수의 대부분이 조금 불필요합니다.

  • firstindex === 0과 같습니다.
  • evenindex % 2 === 0과 같습니다.

또한, trackBy 함수를 제공하는 이점이 없습니다. React, vue, Svelte에서 하는 것 처럼 key 속성을 전달하는 것이 훨씬 쉬워 보입니다. 게다가, 객체의 프로퍼티에 직접 접근하기 위해 객체를 해체할 가능성도 없다고 봅니다. 그것은 제가 평소에 좋아하는 것입니다.

Angular의 팬이 아닌 것처럼 들릴지 모르지만, 저는 팬입니다. Angular는 특히 대규모 엔터프라이즈 애플리케이션의 경우 매우 강력합니다. Rxjs를 사용하는 반응형 프로그래밍 접근 방식을 따르면 프레임워크를 매우 안정적이게 해줍니다. 그럼에도 불구하고, Rxjs의 러닝 커브가 매우 높아 Rxjs는 많은 개발자의 장벽이 될 수 있습니다.

Vue

Vue가 리스트를 렌더링을 처리하는 방식은 Angular가 처리하는 방식과 매우 유사합니다. Vue에서는 v-for 지시문(directive)을 사용하여 배열 기반의 아이템 리스트를 렌더링 할 수 있습니다. items 배열을 반복하여 각 item에 대해 <li> 엘리먼트를 반환합니다. v-for 범위 내에서, 템플릿 표현식은 모든 상위 범위의 프로퍼티에 접근할 수 있습니다. 게다가, v-for는 현재 아이템의 인덱스 값을 위해 옵셔널한 두 번째 별칭(alias)을 제공하며 key 속성도 제공할 수 있습니다.

<ol>
  <li v-for="({ name, logo }, index) in items" :key="`${name}-${index}`">
    <span>{{ index + 1 }}.</span>
    <img class="logo" :src="logo" />
    <span>{{ name }}</span>
  </li>
</ol>

Stackblitz에서 예제를 체험해 볼 수 있습니다.

특이사항

Vue가 다른 프레임워크와 다른 점과 Vue 내에서 리스트를 사용할 때 고려해야 할 사항을 살펴보겠습니다.

객체와 함께 v-for

Vue에서 v-for를 사용하여 객체의 프로퍼티를 반복해서 접근할 수 있습니다. 다른 프레임워크에서는 아직 보지 못했습니다. 물론 다른 프레임워크에서 자바스크립트를 이용해서 동일한 작업을 수행할 수 있습니다. 코드는 다음과 같습니다.

<ul>
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>

범위와 함께 v-for

또 다른 특별한 기능은 정수에 대해 반복할 수 있다는 것입니다. 이 경우 템플릿은 1...n의 범위를 기준으로 여러 번 반복됩니다.

<span v-for="n in 10">{{ n }}</span>

키 속성

React 뿐만 아니라 Vue도 각각의 노드의 아이디를 추적할 수 있는 주요 속성을 제공합니다.

가능한 경우 항상 v-for과 함께 key 속성을 제공하는 것을 권장합니다. - vuejs.org

개인적인 의견

Vue 대한 저의 의견은 Angular와 매우 비슷합니다. 저는 항상 간단한 자바스크립트의 map() 기능을 사용하여 리스트를 반복하는 것을 선호합니다. 하지만 Angular에 비해 Vue의 솔루션은 더 간단해 보이고 덜 복잡해 보입니다.

Svelte

Svelte를 사용하면 각 블록을 사용하여 items 배열을 반복할 수 있습니다. 두 번째 인수를 지정하여 인덱스를 가져올 수 있습니다. 각 리스트의 항목을 고유하게 식별하기 위해 괄호 안에 키 표현식을 제공합니다.()

<ol>
  {#each items as { name, logo } , index (`${name}-${index}`)}
        <li>
          <span>{ index + 1 }.</span>
          <img class="logo" src={logo} />
          <span>{ name }</span>
        </li>
  {/each}
</ol>

Stackblitz에서 예제를 체험해 볼 수 있습니다.

특이 사항

Svelte가 다른 프레임워크와 다른 점과 Svelte 내에서 리스트를 사용할 때 고려해야 할 사항을 살펴보겠습니다.

{:else} 구문

Svelte에서 한 가지 유용한 점은 {:else} 구문을 사용할 수 있다는 것인데, 이 구문은 리스트가 비어 있으면 렌더링됩니다.

<ol>
  {#each items as { name, logo } , index (`${name}-${index}`)}
        <li>
          <span>{ index + 1 }.</span>
          <img class="logo" src={logo} />
          <span>{ name }</span>
        </li>
      {:else}
          <p>No items available!</p>
  {/each}
</ol>

키 속성

다른 모든 프레임워크와 마찬가지로 Svelte는 각 리스트의 항목을 고유하게 식별하는 방법을 제공합니다. 이를 위해 블록에 대해 고유한 식별자 또는 "key"를 지정할 수 있습니다. 이를 통해 우리는 Svelte에게 컴포넌트가 업데이트 될 때 어떤 DOM 노드를 변경할지 알려주고 있습니다.

키는 임의의 객체 일 수 있지만 문자열과 숫자는 객체 자체가 변경되어도 아이덴티티가 유지되므로 문자열과 숫자를 사용하도록 권장합니다. - https://svelte.dev/docs#template-syntax-each

개인적인 의견

Svelte의 문법은 익숙해질 필요가 있습니다. 템플릿에 {:else} 블록을 추가할 수 있는것은 좋습니다. 해당 블록은 자주 수행해야하는 작업이기 때문입니다. #each 블록마다 파괴(Destructuring) 및 휴식(Rest) 패턴을 자유롭게 사용할 수 있는 것도 마음에 듭니다.

마지막 생각

가장 많이 사용되는 4가지 프런트엔드 프레임워크는 모두 리스트를 렌더링 하는 것이 매우 유사합니다. DOM을 효율적으로 업데이트하기 위해 각 항목에 고유한 키를 제공할 수 있는 것과 같이 많은 유사점이 있습니다.

하나의 프레임워크가 완벽한 해결책을 가지고 있다고 말할 수는 없습니다. 궁극적으로, 이것은 취향의 문제입니다. 가장 중요한 것은 한 프레임워크에서 리스트를 렌더링 하는 방법을 알 고 있는 경우 다른 프레임워크에서도 자신의 지식을 적용할 수 있다는 것입니다. 새로운 프런트엔드 프레임워크를 학습하는 것은 다른 프런트엔드 프레임워크의 컨셉을 마스터 했을 때 더 빠르게 할 수 있습니다.

이 글을 재밌게 읽으셨기를 바랍니다. 저는 항상 질문에 대답하는 것이 즐겁고 비판에 개방적입니다. 언제든지 연락주세요.😊

여기 Medium의 모든 컨텐츠에 무제한으로 접근할 수 있는 링크가 있습니다. 이 링크로 가입하시면 추가 비용 없이 소액을 적립해 드립니다.

다음 글을 놓치지 않고 저를 따라와주세요. 저는 타입스크립트, 웹 컴포넌트, 프런트엔드 프레임워크, 소프트웨어 디자인 패턴, 크롬 익스텐션 등 더 많은 주제에 대해 글을 씁니다!🙏

저자

Marius Bongarts는 Accenture Interactive의 소프트웨어 엔지니어링 분석가입니다. 또한 웹 하이라이트 크롬 익스텐션(Web Highlights Chrome Extension)을 만들어 수천 명의 사용자들이 모든 웹 사이트에 텍스트 하이라이트 및 책갈피를 만들 수 있게 했습니다. 태그와 디렉터리를 제공하면 web-highlights.com의 해당 웹 응용 프로그램에서 웹 연구를 쉽게 다시 찾을 수 있습니다. 확인해보세요!


🚀 한글로 된 프런트엔드 아티클을 빠르게 받아보고 싶다면 Korean FE Article(https://kofearticle.substack.com/)을 구독해주세요!

profile
FE Engineer

1개의 댓글

comment-user-thumbnail
2022년 5월 23일

좋은 자료 번역 감사드립니다 :)

답글 달기