IT/react

[리액트]gridjs 로우(행)클릭이벤트 및 색상 표시

generator 2024. 10. 21. 14:52

이번에 진행하는 프로젝트에 처음으로 리액트를 사용하게 되었다.

그리드는 뭘로 사용할까 하다가 gridjs를 정하고 테스트해보는데 디자인도 깔끔하고 사용성도 편리한 거 같았다.

그리고 클릭이벤트를 찾아보는데 뭔가 쉽게 검색이 되지 않았고 

행 변경시에 색상 변경은 기존에 css와 부치는지는 한참을 고생해서 적용했다.

기본으로 제공하는 부분이 동작을 안 해서 어쩔 수가 없었는데 임시방편으로 강제 변경을 진행해 주었다.

혹시 같은 고민을 하고 있다면 다른 부분은 참고를 위해서 넣은 부분이고 클릭이벤트와 그안에 색상 지정하는 부분만 필요하다면 참고하면 될 거 같다. 

import { Grid, h } from 'gridjs';
import "gridjs/dist/theme/mermaid.css";
import React, { useEffect, useState, useRef } from 'react';
import '../../styles/Box.css';

const Stock1 = () => {
  const [data, setData] = useState(null);
  const [selectedCode, setSelectedCode] = useState('005930');
  const [selectedName, setSelectedName] = useState('삼성전자');
  const gridRef = useRef(null); // grid element에 접근하기 위한 ref

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axiosInstance.get('/todaydata');
        const tableData = JSON.parse(response.data.data.list).map(item => 
          [item.RANK, item.NAME, item.CLOSE, item.CHA_PER, item.CHA_DIV, item.CODE]);
        setData(tableData);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();
  }, []);


  useEffect(() => {
    if (data && gridRef.current) {
      const grid = new Grid({
        columns: [
          { id: 'RANK', name: 'RANK', width: '10%' },
          { id: 'NAME', name: 'NAME', width: '40%' },
          { id: 'CLOSE', name: 'CLOSE', width: '20%' },
          {
            id: 'CHA_PER',
            name: 'CHA_PER',
            width: '15%',
            formatter: (cell, row) => {
              const chaDiv = row.cells[4].data;
              const color = chaDiv === 1 ? 'red' : 'blue';
              return h('span', { style: { color: color } }, cell);
            },
          },
          { id: 'CHA_DIV', name: 'CHA_DIV', width: '0%', hidden: true },
          { id: 'CODE', name: 'CDODE', width: '0%', hidden: true }
        ],
        data: data,
        search: true,
        pagination: {
          limit: 2500,
          summary: true
        },
        style: {
          table: {
            width: '100%',
          },
          row: {
            // 선택된 행의 스타일
            selected: {
              backgroundColor: 'lightblue',
            }
          }
        }
      });

      // 이벤트 등록 (rowClick)
      grid.on('rowClick', (event,row) => {
        
        const rowData = row.cells.map(cell => cell.data); // 각 열의 데이터를 배열로 추출
        const rowElement = event.target.closest('tr');
        const rowIndex = Array.from(rowElement.parentNode.children).indexOf(rowElement);
       
        // 모든 행에서 'selected' 클래스 제거
        const rows = rowElement.parentNode.children;
        Array.from(rows).forEach((row) => {
          row.classList.remove('selected');
          // 이전 스타일 초기화
          Array.from(row.cells).forEach(cell => {
            cell.style.backgroundColor = ''; // 모든 셀의 배경색 초기화
          });
        });

        // 현재 선택된 행의 배경색을 변경
        rowElement.classList.add('selected');
        // 선택된 행의 모든 셀에 배경색 적용
        Array.from(rowElement.cells).forEach(cell => {
          cell.style.backgroundColor = '#e6f7ff'; // 선택된 셀 배경색 변경
        });

      });
      
      grid.render(gridRef.current); // grid 렌더링
    }
  }, [data]);


  if (!data) {
    return (
      <div>
        <NavDetail value='stock' />
        <div>Loading...</div>
      </div>
    );
  }

  return (
    <div>      
      <div style={{ display: 'flex', height: 'calc(100vh - 60px)' }}>        
          <div ref={gridRef}></div> {/* Grid가 렌더링될 요소 */}
      </div>
    </div>
  );
};


export default Stock1;