서버 Data 를 Table 형태로 출력하면서 추가적 필요한 내용이 colspan
, rowspan
입니다. 지금까지는 동일한 데이터라고 해도 .map()
함수로 동일한 내용을 그대로 출력함으로써 작업에는 문제가 없지만 동일한 내용이 화면에 반복 출력함으로써 시각적 피로도 및 출력자료에 대한 보다 자유로운 형태 조작이 어려운 한계가 존재합니다.
이번에 React 에서 Table
을 자체제작 형태를 사용하는 것으로 우선 결정한 만큼 이 기능도 추가하는 방법에 대하여 시도한 내용들을 정리해 보도록 하겠습니다. 현재 목표로 하는 내용을 가장 잘 구현한 내용을 vue.js 로 작성한 내용으로 Vue.js - 동적으로 테이블 행 병합하기, 동적 rowspan(1) 를 참고하면 됩니다.
풀어나아갈 문제들을 정리하면 다음과 같습니다.
- 서버에서 출력한 Object Array 를 받는다.
- 받은 Object Array 에서 중복되는 Object 의 Key 와 Value 를 찾는다
- 앞에서 찾은 정보를 활용하여 중복값과 중복 횟수를 판단할 기준으로 활용한다
- 중복횟수 기준 데이터를 활용하여 원본 Object array 에서 중복된 데이터는 null 로 변환한다
- 각 열들의 중복데이터를 추가한다
최종형태
role
의 값을 기준으로 연산을 통해 roleRowSpan
값을 추가한다. roleRowSpan
값을 기준으로 셀 병합 크기 및 노출하지 않을 값의 크기를 결정하는 방법으로 해결 가능 합니다.
interface RowData {
name: string;
age: number;
role?: string;
roleRowSpan?: number; // Number of rows to span for the role cell
}
const data: RowData[] = [
{ name: "Alice", age: 30, role: "Manager", roleRowSpan: 1 },
{ name: "Bob", age: 25, role: "Tester" , roleRowSpan: 2 },
{ name: "Charlie", age: 35 }, // Role cell will be empty due to rowspan
];
입력값을 위와 같이 변환을 완료했다면 템플릿에서는 이에 적합한 조건식만 추가하면 됩니다.
const Table = () => {
return (
<table>
<tbody>
{data.map((row, index) => (
<tr key={index}>
<td>{row.name}</td>
<td>{row.age}</td>
{index === 0 || row.role !== ""
?
(
<td rowSpan={row.roleRowSpan}>
{row.role}
</td>
)
:
null
}
</tr>
))}
</tbody>
</table>
);
}
JavaScript
useMemo()
에서 다음과 같은 내용으로 중복여부를 확인 한 뒤, 중복갯수를 기준으로 rowSpan
값을 생성하게 됩니다. 실제 결과에서는 적용하지 못했는데, 이유는 checkBox
로 개별 라인별 숨기기를 하게되면 rowSpan
값이 그대로 적용됨에 따라 테이블이 깨지게 되었기 때문입니다. 향후에 이를 적용할 때를 대비하여 작업 결과를 정리해 보면 다음과 같습니다.
// 중복되는 갯수확인
function countDuplicates(array:(string|number)[]) {
let countMap: any = {};
array.forEach(function(i){countMap[i] = (countMap[i]||0)+1;});
return countMap
}
// useMemo 로 수집데이터 최적화
const data = useMemo(() => {
let checkName: any = {}
const names: string[] = items.map((item) => {
return item.type + item.menu
})
const checkCounts = countDuplicates(names) // Add NewKey
items.map((item) => {
if(checkName[item.type + item.menu]){
item.rowSpan = 0
} else {
item.rowSpan = checkCounts[item.type + item.menu]
checkName[item.type + item.menu] = 1
}
})
return [...items].sort(
function (a,b) {
return a['id'] - b['id']
}
)
},[items])
참고사이트
https://yongbeomkim.github.io/02js/2023-07-04-obj-sort.html
https://sisiblog.tistory.com/313
https://ordinary-code.tistory.com/8
https://velog.io/@tjdud0123/javascript-map-filter-%ED%95%A8%EC%88%98
https://stackoverflow.com/questions/19395257/how-to-count-duplicate-value-in-an-array-in-javascript
https://gurtn.tistory.com/204
https://stackoverflow.com/questions/38824349/how-to-convert-an-object-to-an-array-of-key-value-pairs-in-javascript