#41.TIL | localStorage사용하여 DataGrid Column저장 & 로딩할때 props Column과 비교하여 업데이트해주기 (feat. storybook)

Seongjae Hwang·2022년 4월 30일
2


위 화면과 같이 DataGrid의 default column순서를 변경 시켜 내가 중요하다고 생각되는 정보의 순서만 보고 싶은데, 새로고침했을때 다시 default 순서로 돌아간다면 사용자에게 하여금 매우 불편한 경험을 느끼게 해준다.(매번 똑같은 정렬을 해야 하니)

그렇다면, localStorage를 활용하여 각자의 custom한 column순서를 저장하고, 이를 로드할때 불러온다면 저장된 값을 사용자에게 보여줄 수 있다.

그런데,

만약 개발계에서 데이터가 업데이트돼서
1. 새로운 column이 추가되거나
2. 기존 column이 삭제 되거나
3. 기존 column값이 변경된다면

사용자는 localStorage에 저장된 값을 불러와 로드하기 때문에, 사용자에게 변경사항이 있을때 마다

"개발자도구 켜신 다음 Application탭을 클릭하시고, localStorage에서 key 값이 customOrderColumn인것을 찾아서 마우스 오른쪽 버튼 누르시고 delete 해주실래요?"

라고 할 수 없으니, 로드될때 마다 props로 받은 default column과 localStorage에 저장된 customOrderColumn을 비교하여 update시켜줘야 한다. 그렇다면 로드할때 로직이 동작해야 하는데, 우선 벤다이어그램을 그려보면 아래와 같다.

위와 같은 상황에서 A 혹은 B에 값이 있다면 customOrderColumn이 수정된 default column의 싱크를 못따라가고 있다는 뜻과 같고, 수정된 데이터를 update시켜주면 된다.

그런데,

여기서 주의해야 할 점은 단순히 set state를 통해 새로운 column을 덮어버리면 customOrderColumn에 저장된 순서가 깨져버리는 불상사가 발생하기 때문에,
1. 데이터의 싱크
2. 사용자가 저장한 customOrderColumn의 순서

를 지켜서 update해야 한다.
(따라서, 교집합은 default column이 아닌 customOrderColumn으로 filter메서드 사용.)

import {useEffect, useState} from "react"
import { DataGridPro } from "@mui/x-data-grid-pro";


export default function ChangeColumnDataGrid({rows,columns}){
    const [newColumns,setNewColumns] = useState([])
    
    useEffect(() => {
      loadData();
    }, []);

  // targetArr와 compareArr의 교집합, 차집합 찾는 함수 포멧
    const filteringIncludesObj = (targetArr, compareArr, includes) => {
      if (includes) {
       return targetArr.filter(obj => JSON.stringify(compareArr).includes(JSON.stringify(obj)))
      }
      else{
        return targetArr.filter(obj => !JSON.stringify(compareArr).includes(JSON.stringify(obj)))
      }
    };

    const loadData = () => {
      //localStorage에 저장돤 customColumn
      const savedColumOrder = JSON.parse(localStorage.getItem("columnOrder"));
      //localStorage에 저장돤 값이 없다면 set default column
      if (savedColumOrder === null) {
        setNewColumns(columns);
        return;
      } 
      // default와 custom column의 대칭 차집합
      const symmetricDifferenceColumns = filteringIncludesObj(savedColumOrder, columns, false).concat(filteringIncludesObj(columns, savedColumOrder, false));
      // default와 custom column의 대칭 차집합에 값이 있을 경우 (벤다이어그램 A와 B 둘 중 값이 하나라도 있으면,)
      if(symmetricDifferenceColumns.length>0){
      // 교집합(벤다이어그램의 C)
        const intersectionColumns = filteringIncludesObj(savedColumOrder, columns, true)
      // (벤다이어그램의 A)
        const differnceColumnsDefine = filteringIncludesObj(symmetricDifferenceColumns, columns, true)
      // (벤다이어그램의 B)
        const differnceColumnsSaved = filteringIncludesObj(symmetricDifferenceColumns, savedColumOrder, true)
      // (벤다이어그램의 A의 값이 있으면, 교집합에 추가된 A값 update)
        if(differnceColumnsDefine.length>0){
          const updateColumns = [...intersectionColumns, ...differnceColumnsDefine]  
          setNewColumns([...updateColumns])
          localStorage.setItem("columnOrder", JSON.stringify([...updateColumns]));
          return
        }
      // (벤다이어그램의 B의 값이 있으면, 교집합으로 update)
        if(differnceColumnsSaved.length>0){
          setNewColumns([...intersectionColumns])
          localStorage.setItem("columnOrder", JSON.stringify([...intersectionColumns]));
          return
        }
      }
      // (차집합이 없을 경우, custom column값으로 update)
        setNewColumns(savedColumOrder);
    };

  	  // column순서가 바뀔때, oldIndex와 targetIndex를 받아 switching해주고, save하는 함수 포멧
    const saveData = (arr, oldIndex, targetIndex) => {
      if (targetIndex >= arr.length) {
       return arr
      }
      arr.splice(targetIndex, 0, arr.splice(oldIndex, 1)[0]);
      setNewColumns([...arr]);
      localStorage.setItem("columnOrder", JSON.stringify([...arr]));
    };
   

  return(
  <div style={{ height: "600px" }}>
    <DataGridPro 
    hideFooter={true}
    disableSelectionOnClick= {false}
    getRowId={(row) => (row.ticker)}
    rows={rows}
    columns={newColumns}
    onColumnOrderChange={e => saveData(newColumns,e.oldIndex,e.targetIndex)}
    />
  </div>)
};

결과

1. saveData

2. loadData

1). A.length>0


2). B.length>0


3). A.length + B.length === 0


데이터 싱크가 맞춰진 상태이므로 customOrderColumn 로드

profile
Always Awake

0개의 댓글