느릿늘있

클로저를 활용한 grid rowid 구현 본문

삽질로그

클로저를 활용한 grid rowid 구현

JHKim93 2024. 10. 12. 22:37

  우선 이 글은 클로저에 대해 자세하게 설명하는 글은 아니기 때문에 클로저에 대한 설명은 아래 링크로 대체합니다. :0

https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures

 

클로저 - JavaScript | MDN

클로저는 주변 상태(어휘적 환경)에 대한 참조와 함께 묶인(포함된) 함수의 조합입니다. 즉, 클로저는 내부 함수에서 외부 함수의 범위에 대한 접근을 제공합니다. JavaScript에서 클로저는 함수 생

developer.mozilla.org

  회사에서 grid로 데이터를 그려야하는 경우가 정말 많습니다. 이번에 grid 관련해서 발생한 결함을 클로저를 활용해서 해결했는데 해당 내용을 간략하게 기록하고자 합니다. 우선, 문제 상황을 설명하자면 다음과 같습니다.

  첫번째로 이와 같이 그리드에 데이터 3개를 추가합니다.

  두번째로 중간 데이터를 삭제합니다.

  세번째로 새로운 데이터를 추가하면 위 이미지와 같이 3번 데이터 자리에 4번 데이터가 덮어쓰여지는 현상이었습니다.

  이런 현상이 발생한 원인은 그리드의 rowid를 계산하는 방식에 있었는데요. 기존 코드가 아래와 같이 작성되어 있었습니다.

// 변수명은 이해하기 쉽게 추상화하였습니다.
// 추가할 row의 rowId는 이전에 추가한 row의 개수 + 원본 데이터에 이미 존재하던 row의 개수 + 1
this.addRow.rowId = prevAddedRows.length + originalRows.length + 1

   이미지로 설명한 과정에 이 코드를 적용하면 추가 데이터 1의 rowId는 3, 추가 데이터 2의 rowId는 4, 추가 데이터 3의 rowId는 5입니다. 거기서 추가 데이터 2를 삭제하더라도 기존에 부여된 rowId는 변하지 않죠. 문제는 여기서 네번째 추가 데이터를 추가하면 현재 추가되어 있는 row의 개수는 2, 원본 데이터의 개수는 2 여기에 1을 더하니 2+2+1=5가 나오게 됩니다. 이는 추가 데이터 3의 rowId와 동일하고 추가 데이터 4가 이를 덮어쓰게 되는 것이죠.

  이를 해결하기 위해 클로저를 사용해보았습니다!

rowIdController = () => {
    const rowId = prevAddedRows.length + originalRows.length + 1;
	
    const getRowId = () => {
    	return rowId;
    }
    
    const increaseRowId = () => {
    	rowId++;
    }
    
    return { getRowId, increaseRowId };
}

// 현재 class 프로퍼티로 선언
rowIdService = rowIdController();

// grid row 추가하는 함수
addRow = (curAddRow) => {
    // add 가능 여부를 판단하는 코드들..........
    
    // OK면
    this.rowIdService.increaseRowId();
    curAddRow.rowId = this.rowIdService.getRowId();
}

  정확하진 않지만 대충 이와 같은 모습이고 이렇게 코드를 작성한 의도는 다음과 같습니다.

  1. rowId의 할당 로직은 최초에 한 번만 사용하면 된다.
  2. 그 이후로는 계속 1씩 증가하면 된다.

   이를 구현하기에 클로저의 개념을 사용하면 안성맞춤이라고 생각이 들었고 그 이유는 클로저가 아래와 같이 동작하기 때문입니다.

  1. 원래는 rowIdService가 rowIdController를 실행함에 따라 rowId 값이 초기화 되었다가 그 스코프가 종료됨에 따라 메모리에서 가비지 컬렉팅 대상이 되어 한다.
  2. 하지만 rowIdService가 계속 참조되고 있고  rowIdService가 increaseRowId와 getRowId를, 이들의 렉시컬 스코프에서는 rowId를 참조하고 있는 연쇄적인 참조가 발생하고 있다. (클로저)
  3. 이로 인해 rowId가 가비지 컬렉팅 대상에서 제외되고 increase와 get으로만 접근 가능하기 때문에 절대 감소하지 않는 캡슐화된 코드의 모습을 갖추게 되었다.

  팀장님도 코드를 설명드리고 기능이 정상 동작함을 보여드리니 오케이 해주셨지만 실무에 이렇게 써보는 것은 처음이라서 솔직히 아직도 이게 좋은 코드라는 확신은 없습니다. ㅎ_ㅎ,,, 하지만 공부한 내용을 실무에 적용해보고 이렇게 블로그로 다시 한 번 정리하는 과정 자체가 하나의 올바른 성장 과정이라는 것은 확신하기에 이렇게 한 번 작성해보았습니다! 감사합니다.