React와 Vue 리스트 렌더링에서 핵심 props 이해하기
Min-jun Kim
Dev Intern · Leapcell

소개
현대 프론트엔드 개발에서 동적 데이터 리스트를 효율적으로 렌더링하는 것은 응답성이 뛰어나고 사용자 친화적인 애플리케이션을 구축하는 데 있어 초석입니다. 소셜 미디어 피드, 쇼핑 카트, 사용자 데이터 테이블을 생각해 보세요. 이 모든 것이 리스트에 크게 의존합니다. 그러나 렌더링 엔진이 이러한 리스트 내의 변경 사항을 식별하는 데 도움을 줄 수 있는 적절한 메커니즘 없이는 성능이 저하될 수 있으며 상태 관리와 관련된 미묘한 버그가 발생할 수 있습니다. 이것이 바로 React와 Vue와 같은 프레임워크에서 key props가 등장하는 지점입니다. 이는 차이를 식별하여 재귀 알고리즘에 중요한 정보를 제공하여 UI를 지능적으로 업데이트하고 모든 항목을 처음부터 다시 렌더링하는 것을 방지합니다. 최적화되고 강력한 리스트 렌더링 코드를 작성하려는 프론트엔드 개발자에게는 그 중요성과 내부 작동 방식에 대한 이해가 필수적입니다.
조정 엔진 및 리스트 업데이트
key props 자체에 대해 자세히 알아보기 전에 React와 Vue가 DOM을 효율적으로 업데이트하는 데 사용하는 핵심 메커니즘인 "조정 엔진(Reconciliation engine)"의 개념을 이해하는 것이 중요합니다.
핵심 용어:
- 가상 DOM (Virtual DOM): 실제 DOM의 가볍고 메모리 내 표현입니다. 애플리케이션의 상태가 변경되면 프레임워크는 새로운 가상 DOM 트리를 생성합니다.
- 조정 (Reconciliation): 새로운 가상 DOM 트리를 이전 트리와 비교하여 변경된 내용을 식별하는 프로세스입니다.
- 차이점 알고리즘 (Diffing Algorithm): 조정 중에 실제 DOM을 업데이트하는 데 필요한 최소한의 변경 사항을 결정하는 데 사용되는 특정 알고리즘입니다.
- DOM 조작 (DOM Manipulation): 브라우저의 문서 객체 모델을 직접 수정하는 비용이 많이 드는 프로세스입니다. 조정 엔진의 목표는 이를 최소화하는 것입니다.
key props 없이 리스트를 렌더링할 때 React와 Vue는 단순하고 직관적인 비교를 수행합니다. 항목이 추가, 제거 또는 순서 변경되면 기본 동작은 배열에서의 위치를 기준으로 요소를 비교하는 것입니다. 이는 비효율적인 업데이트를 유발하고, 더 중요하게는 입력 필드 값이나 포커스와 같은 내부 컴포넌트 상태를 잃게 할 수 있습니다.
key Props의 역할
key props는 리스트의 각 항목에 안정적인 식별자를 제공합니다. React 또는 Vue가 key props가 있는 요소를 볼 때, 조정 알고리즘은 이러한 키를 사용하여 이전 리스트의 항목과 새 리스트의 항목을 일치시킵니다.
작동 방식:
- 안정적인 식별자:
key는 각 리스트 항목에 대해 고유하고 안정적인 식별자여야 합니다. 이상적으로는 데이터 자체(예: 데이터베이스 ID)에서 가져옵니다. - 효율적인 차이점 식별: 리스트가 업데이트될 때 조정 엔진은 먼저 요소의
key를 비교합니다.key가 새 리스트에는 있지만 이전 리스트에는 없으면 새 컴포넌트/요소가 생성됩니다.key가 이전 리스트에는 있지만 새 리스트에는 없으면 해당 컴포넌트/요소가 파괴됩니다.key가 두 리스트 모두에 있으면 처음부터 다시 렌더링하는 것이 아니라 컴포넌트/요소가 이동(위치가 변경된 경우)하거나 업데이트(props가 변경된 경우)됩니다. 내부 상태는 유지됩니다.
고유하고 안정적인 키가 중요한 이유
- 고유성: 키는 동일한 리스트 내의 형제 요소 중에서 고유해야 합니다. 중복 키는 엔진이 해당 요소를 고유하게 식별할 수 없으므로 예측할 수 없는 동작과 잠재적인 버그를 초래합니다.
- 안정성: 키는 다시 렌더링되는 동안 동일한 항목에 대해 일관되게 유지되어야 합니다. 항목이 추가, 제거 또는 순서 변경될 수 있는 경우에는
index를 키로 사용하는 것이 일반적으로 권장되지 않습니다.index를 키로 사용하는 문제점: 리스트 시작 부분에 항목을 삽입하면 후속 모든 항목의 색인이 변경됩니다. 조정 엔진은 기존 모든 항목의 키(색인)가 변경된 것으로 인식하여 대부분 또는 모든 리스트 항목을 다시 렌더링하고 내부 상태를 잃게 됩니다.
React(Vue에도 동일하게 적용됨)의 간단한 예제를 통해 설명해 보겠습니다.
시나리오 1: index를 키로 사용 (문제 발생)
새 작업을 목록의 시작 부분에 추가할 수 있는 작업 목록을 고려해 보세요.
import React, { useState } from 'react'; function TaskListIndexKey() { const [tasks, setTasks] = useState([ { id: 1, text: 'Learn React', completed: false }, { id: 2, text: 'Build a project', completed: false }, ]); const [newTaskText, setNewTaskText] = useState(''); const addTask = () => { if (newTaskText.trim() === '') return; const newId = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1; setTasks([{ id: newId, text: newTaskText, completed: false }, ...tasks]); // 맨 앞에 추가 setNewTaskText(''); }; return ( <div> <input type="text" value={newTaskText} onChange={(e) => setNewTaskText(e.target.value)} placeholder="New task" /> <button onClick={addTask}>Add Task</button> <ul> {tasks.map((task, index) => ( // 문제: index를 키로 사용 <li key={index}> {task.text} <input type="checkbox" checked={task.completed} onChange={() => { /* 토글 로직 */ }} </li> ))} </ul> </div> ); } export default TaskListIndexKey;

