현대 웹 개발에서는 사용자와 동적으로 상호작용하는 UI가 필수입니다.
특히, Vue.js와 같은 프론트엔드 프레임워크를 사용하면 ref 객체와 computed, watch 등을 통해 반응형 데이터를 쉽게 다룰 수 있습니다.
이번 글에서는 Vue의 ref로 정의된 배열 데이터를 기반으로, 동적으로 테이블 헤더 객체를 구성하는 방법을 알아보겠습니다.
문제 정의
Vue에서 ref<T[]>([])로 선언된 배열 items를 기반으로 테이블 데이터를 그리고, 이 데이터와 관련된 헤더 영역도 함께 구성하려는 요구가 종종 발생합니다. 예를 들어, 다음과 같은 구조를 생각해볼 수 있습니다:
const items = ref<T[]>([]);
const dataList = items.value;
dataList가 존재하고,
그 길이가 0보다 클 경우에만 특정 처리(예: 총계 row 생성)를 하고 싶다면 아래처럼 작성할 수 있습니다:
if (dataList.length > 0) {
getTotalRows(tableDatas, headerTotal);
}
이처럼 배열 길이를 체크해 조건문을 작성하면 불필요한 연산을 방지할 수 있어 성능 면에서도 이점이 있습니다.
동적으로 헤더 객체 배열 구성하기
데이터 테이블을 구성할 때, 헤더 부분도 데이터 기반으로 유연하게 변경되기를 원하는 경우가 많습니다. 예를 들어, 다음과 같은 배열을 기반으로 각 항목을 헤더로 사용하려면 어떻게 해야 할까요?
headerPeriod.value?.gridHeadList = ["1월", "2월", "3월"];
이 배열을 다음과 같은 형태로 객체화하고 싶다면?
[
{ headerTitle: "1월", colSpan: 2 },
{ headerTitle: "2월", colSpan: 2 },
{ headerTitle: "3월", colSpan: 2 }
]
자바스크립트의 map() 함수를 사용하면 매우 간단하게 구현할 수 있습니다.
map() 함수와 Spread Operator 활용법
아래는 map()과 spread operator (...)를 이용해 동적으로 헤더 배열을 구성한 코드 예시입니다:
const headerGridHeadListObj = [
{ headerTitle: glossaryWord("9000001067"), colWidth: 11 }, // total
...headerPeriod.value?.gridHeadList.map((item) => ({
headerTitle: item,
colSpan: 2
})) || []
];
코드 해설
- map()은 gridHeadList 배열의 각 요소(item)를 원하는 형식의 객체로 변환합니다.
- ...(spread operator)는 map() 결과인 배열을 바깥 배열의 개별 요소로 풀어줍니다.
- || []는 headerPeriod.value?.gridHeadList가 undefined일 경우를 대비한 fallback 처리입니다.
이 코드를 실행하면 최종적으로 다음과 같은 결과를 얻게 됩니다:
[
{ headerTitle: "합계", colWidth: 11 },
{ headerTitle: "1월", colSpan: 2 },
{ headerTitle: "2월", colSpan: 2 },
{ headerTitle: "3월", colSpan: 2 }
]
자주 하는 실수: 배열 안에 배열 넣기
많은 개발자들이 실수로 아래처럼 작성하는 경우가 있습니다:
const wrongHeader = [
{ headerTitle: "합계", colWidth: 11 },
headerPeriod.value?.gridHeadList.map(item => ({ headerTitle: item, colSpan: 2 }))
];
이렇게 하면 headerPeriod.value?.gridHeadList.map(...)이 배열로 들어가기 때문에, 결과는 배열 안에 배열이 되는 잘못된 구조입니다.
✅ 정답은?
반드시 ... spread 연산자를 사용하여 배열을 풀어서 넣어야 합니다.
Optional Chaining과 Fallback 처리
JavaScript에서 optional chaining (?.)을 사용하면, null이나 undefined 값이 접근 시 오류를 방지할 수 있습니다. 여기에 || []와 같이 fallback 값을 제공하면 안전성과 안정성을 동시에 확보할 수 있습니다:
...headerPeriod.value?.gridHeadList.map(...) || []
이러한 코딩 패턴은 다음과 같은 상황에서 매우 유용합니다:
- Vue.js에서 동적으로 데이터를 바탕으로 테이블을 구성할 때
- 외부 API 데이터에 따라 UI가 달라져야 할 때
- 가변적인 컬럼 구조를 가진 엑셀 스타일 테이블을 만들 때
Spread operator와 map() 함수는 JavaScript에서 매우 자주 쓰이며, 위와 같이 안전하게 결합하면 가독성도 좋고 에러도 방지할 수 있습니다.
'스마트웹앱콘텐츠전문가' 카테고리의 다른 글
카카오 로그인 연동부터 사용자 정보 조회까지 단계별 설명 (0) | 2025.04.09 |
---|---|
지리공간 데이터 분석의 핵심! 벡터 데이터 유형 완벽 가이드 (0) | 2025.04.09 |
MyBatis 3.x에서 <property> 사용이 제한되는 이유와 해결 방법 (0) | 2025.04.02 |
MyBatis SQL 관리의 핵심! <include> 태그와 property 사용법 정리 (0) | 2025.04.02 |
MyBatis 동적 SQL 태그 완벽 가이드: 조건별 쿼리 생성하기 (0) | 2025.03.26 |