포커스 및 선택 (Focus & Active Row)
셀 클릭과 selectedRowKey를 연결해 현재 선택된 행을 시각적으로 강조하는 방법을 학습합니다.
import * as React from 'react';
import { AXDataGrid, AXDGColumn } from '@axboot/datagrid';
import DataGridContainer from '../components/DataGridContainer';
import { useContainerSize } from '../hooks/useContainerSize';
interface Props {}
interface IListItem {
no: number;
id: string;
title: string;
writer: string;
createAt: string;
}
const list = Array.from(Array(1000)).map((v, i) => ({
values: {
no: i,
id: `ID_${i}`,
title: `title_${i}`,
writer: `writer_${i}`,
createAt: `2022-09-08`,
},
}));
export default function FocusExample(props: Props) {
const [selectedRowKey, setSelectedRowKey] = React.useState<number>();
const [columns, setColumns] = React.useState<AXDGColumn<IListItem>[]>([
{
key: 'id',
label: '아이디 IS LONG !',
width: 100,
},
{
key: 'title',
label: '제목',
width: 300,
itemRender: ({ values }) => {
return (
<>
{values.writer} / {values.title}
</>
);
},
},
{
key: 'writer',
label: '작성자',
width: 100,
itemRender: ({ values: values }) => {
return <>{values.writer} / A</>;
},
},
{
key: 'createAt',
label: '작성일',
width: 100,
sortDisable: true,
},
]);
const containerRef = React.useRef<HTMLDivElement>(null);
const { width: containerWidth, height: containerHeight } = useContainerSize(containerRef);
return (
<>
<b>selectedRowKey</b> : {selectedRowKey}
<br />
<br />
<DataGridContainer ref={containerRef}>
<AXDataGrid<IListItem>
width={containerWidth}
height={containerHeight}
headerHeight={35}
data={list}
columns={columns}
onChangeColumns={(columnIndex, { width, columns }) => {
console.log('onChangeColumnWidths', columnIndex, width, columns);
setColumns(columns);
}}
onClick={({ item }) => {
// console.log('item.id', item.id);
setSelectedRowKey(item.no);
}}
rowKey={'no'}
selectedRowKey={selectedRowKey}
/>
</DataGridContainer>
</>
);
}import * as React from 'react';
import './DataGridContainer.css';
interface DataGridContainerProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
}
/**
* Keeps a DataGrid in a measured, fixed layout box.
*
* AXDataGrid's rendered root is absolutely positioned within this relative
* container. This makes a ResizeObserver measurement authoritative when a
* surrounding flex or grid layout shrinks as well as when it expands.
*/
const DataGridContainer = React.forwardRef<HTMLDivElement, DataGridContainerProps>(
({ className, ...rest }, ref) => (
<div ref={ref} className={`data-grid-container ${className ?? ''}`.trim()} {...rest} />
),
);
DataGridContainer.displayName = 'DataGridContainer';
export default DataGridContainer;.data-grid-container {
position: relative;
width: 100%;
height: 400px;
overflow: hidden;
font-size: 13px;
}
.data-grid-container > .axdg-root {
position: absolute;
inset: 0;
}import * as React from 'react';
export function useContainerSize(ref: React.MutableRefObject<HTMLElement | null>, additionalDeps: unknown[] = []) {
const [width, setWidth] = React.useState(0);
const [height, setHeight] = React.useState(0);
const resizeObserver = React.useRef(
new ResizeObserver(entries => {
if (entries.length !== 1) {
throw new Error('Invalid Container length');
}
const [entry] = entries;
const { width, height } = entry.contentRect;
setWidth(width);
setHeight(height);
}),
);
React.useEffect(() => {
if (!ref.current) return;
const observer = resizeObserver.current;
const element = ref.current;
setWidth(element.clientWidth);
setHeight(element.clientHeight);
observer.observe(element);
return () => {
observer.unobserve(element);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...additionalDeps, ref]);
return {
width,
height,
};
}1. 언제 사용하며 왜 필요한가요?
목록과 상세 영역을 연결할 때처럼 사용자가 클릭한 행을 계속 강조해야 하는 경우 selectedRowKey를 사용합니다. onClick에서 원본 행의 키를 상태로 저장하고, 그 값을 selectedRowKey로 다시 전달하는 제어형 패턴입니다.
2. 실무 완성형 예제: 선택 행 강조 및 상세 뷰어 연동
import React, { useState } from 'react';
import { AXDataGrid, type AXDGColumn, type AXDGDataItem } from '@axboot/datagrid';
interface ArticleItem {
id: number;
title: string;
author: string;
createdAt: string;
}
export default function FocusGrid() {
const [selectedKey, setSelectedKey] = useState<string | number>(2);
const [data] = useState<AXDGDataItem<ArticleItem>[]>([
{ values: { id: 1, title: 'AXBOOT DataGrid v1.11 출시 안내', author: '관리자', createdAt: '2026-08-10' } },
{ values: { id: 2, title: '고성능 가상 스크롤 렌더링 최적화 팁', author: '기술팀', createdAt: '2026-08-12' } },
{ values: { id: 3, title: 'React 19 호환성 및 타입스크립트 지원', author: '프론트엔드', createdAt: '2026-08-15' } },
]);
const columns: AXDGColumn<ArticleItem>[] = [
{ key: 'id', label: '번호', width: 70, align: 'center' },
{ key: 'title', label: '제목', width: 320 },
{ key: 'author', label: '작성자', width: 100, align: 'center' },
{ key: 'createdAt', label: '등록일', width: 120, align: 'center' },
];
return (
<div>
<AXDataGrid<ArticleItem>
width={650}
height={220}
columns={columns}
data={data}
rowKey="id"
selectedRowKey={selectedKey} // 선택된 행의 고유 키 (Active 스타일 적용)
onClick={({ item }) => {
setSelectedKey(item.id);
}}
/>
</div>
);
}