SongShop 프로젝트 - 트러블 슈팅

송현섭 ·2024년 7월 15일
0

에러 핸들링

목록 보기
11/13

트러블 슈팅

  • 이번 프로젝트 진행 과정에서 좀 난항을 겪은 부분이 있어 블로그에 기술하고자 한다. 두 가지 건으로 좀 시간을 잡아먹었는데 사실 트러블 슈팅이라기 보다는 그냥 개인적으로 겪은 어려움정도라고 보는 게 좋은 듯 하다.

  • 어려움을 겪던 부분은 subCategory select 의 옵션값을 지정해주는 부분이었다. 본래 생각이 없었는데 여기는 재고 추가 버튼으로 여러 개의 생성이 가능한 Stock 컴포넌트의 하위에 포함된 요소다. 그리고 이 각 stock에 맞게 select 가 독립적으로 존재하는데 select 들 끼리 option값을 공유하는 문제였다.

  • 다른 문제 하나는 그냥 단순히 어떤 특정 값 전달에 있어 받아오는 props 에서 null을 받으면서 생기는 사소한 문제였다. 이 부분도 후술할 예정.




문제점 1 - Component의 각 Select 이 Option 값을 공유

  • 내 프로젝트에서는 위처럼 재고버튼을 누르면 stocks에 새 값이 추가되고, 이 값 list를 map으로 뿌려서 그 수 만큼 Stock 컴포넌트를 생성해서 보여주고 있었다.



  • 해당 Stock 컴포넌트 내에서는 직접 만든 공통 커스텀 Select 컴포넌트에 각 select Type 에 맞게 props와 id값을 넘겨주어 각각 독립적인 Select로서 사용되고 있었다.




  • 저기서 넘겨지는 props 들 중에는 hooks 안에서 선언된 각 Select에 맞춰진 핸들링 함수도 있다. 이 함수들은 hooks 안에 정의되어 있고, 현재 내부함수로 사용중이다. 정확히 말하자면 내부에서 로직을 정의내린다음 CustomSelect 로 각각 넘겨줄 때 props 의 onChnage 라는 key 값에 value로 함수 자체를 넘겨주고 있는 것이다.
    이 방식이 좋은지는 잘 모르겠다. 보통 hooks 는 내부에 정의한 함수들을 꺼내서 적절히 사용하여 코드를 간편화하고 더 쉽게 상태를 관리하는 것으로 알고 있는데 좀 더 공부가 필요함을 느끼는 부분이다.




  • 문제는 여기 CustomSelect 에서 넘겨받는 rest들 중 options 의 select 옵션항목들이 모든 Stock의 Select 와 함께 동기화된다는 것이다.
    (ex. A Stock 에서 select 옵션 중 하나를 선택하면 이는 비활성화됨. 이후 B Stock에서 select를 클릭하면 보이는 옵션 항목에 A에서 선택한 옵션이 비활성화 처리되어 있는 상태를 유지.)
  • 나는 쇼핑몰 판매자 입장에서 재고를 추가하고, 그 재고 수량을 지정하는 기능을 구현하려 한 것이기에 한 재고에 대해 7개라는 수량을 지정했다면, 다른 재고품목에 대해 7개 이외의 값을 선택하는 것은 어색하고 어딘가 맞지 않은 방식이라고 생각했기에 이는 수정될 필요가 있었다.




  • Options 는 각 Option 의 상수값들을 import 해와서 이 default를 초기값으로 recoil state에 저장하여 전역상태로 사용하고 있다. 여기서 저 각 options 들은 배열안에 객체들로 존재하는 데이터들이기에 주소값 참조가 이루어져 모든 select가 공유되고 있던 것이다.

  • 이 부분을 해결하고자 굉장히 많이 고민했다. 로직 구상에 대한 어려움이라기 보다는 이렇게 하는게 맞을까? 더 좋은 방법은 없는걸까로 고민한 시간이 더 많았다.




  • 결과적으로는 이 방식을 택했다. 처음에 default 상수값을 가지고 각 객체에 상수가 담긴 length 3의 배열을 생성했다. 그리고 stocks 를 생성할 때 stocks 관련 데이터정보가 담긴 객체에 index 값을 추가하여 후에 options 값을 변경할 때 이 index 값으로 atom의 state에 접근할 수 있도록 하였다.

  • 참고로 저기 deepCopy 는 직접만든 커스텀 유틸함수로, 배열안에 넣은 요소각각을 순서대로 깊은복사 처리 후 반환해 준다. 각 Options는 별개로 인식되어야 하기에 주소값을 독립적으로 재할당했다.




  • 각 StockComponent 에서는 이렇게 useHooks를 호출하는데 이 때 인자로 props를 통해 넘겨받은 stock 의 index값을 전달한다.



  • 넘겨진 index값은 이렇게 hooks 안의 handleCountChange 에서 기존에 저장되어 있던 값에 접근하기 위해 사용되어진다.

  • selectOptions 는 isdisabled를 선택된 값에 맞게 다시 재설정한 최종값으로 각 Stocks에 대한 options 들 중 우리가 선택한 stocks의 Index의 값만 바꿔치기하여 적용한다.




+a) 알게된 점 하나 - 리터럴 템플릿을 활용한 form데이터 저장 구조잡기

  • 필자는 React-Hook-Form으로 각 Select의 입력값(선택된 값)을 관리하고 있다. Select는 외부 라이브러리이기 때문에 hook form의 register가 아닌 Controller 에서 직접 name을 지정해서 FormData 에 추가가 가능하다.

  • stocks 의 경우 각 stocks 에 대해 품목 사이즈, 개수 등의 정보를 구분해서 담아야 나중에 이 값을 불러 사용할 때 어떤 사이즈에 대해 몇 개의 재고가 있다를 인지시켜줄 수가 있다. 그러나 저 name에 그냥 string 값이 들어가면 depth 가 없이 그냥 같은 위치에 key, value로 데이터가 들어오고 있었다.



  • 이 부분을 리터럴템플릿 형식으로 해결가능하다. 이것도 문법적으로 기초적인 부분일텐데 본인은 잘 몰랐다..(구글링하다 알게 됨)

  • 위처럼 작성하게 되면 stocks 라는 key 값으로 배열하나를 만들고 그 안에 내가 지정할 nameValue 가 들어간다. 이후 그 value값을 key로 하는 count value를 .표기법으로 추가해줄 수 있다.





  • 이후 확인해보면 원하던 형식대로 데이터가 담겨서 출력되는 것을 확인가능하다.






문제점 2 - onchange로 넘겨받는 Options의 Select 값에 접근이 불가능한 문제 (null값 오류)

  • 앞서 사용하는 공통 Selector 에서 Controller 에서 제공하는 onChange를 사용하면 내부적으로 이벤트를 캐치해서 사용자가 선택한 옵션값을 인자로 넘겨준다. 그러나 여기서 오류가 발생했다.
    Count, Size 조정에 대한 Select 옵션값은 잘 넘어오는데, Category Select에 대해서만 select.value 에 접근할 수 없다는 에러를 발생시키는 것이다.



  • 왜 이럴까...콘솔 로그로도 select 값은 잘 찍혀나온다. 심지어 저 onChange에 바인딩 된 로직에서 select를 콘솔로 찍어도 그 값이 잘 나온다. 다만 객체에서 데이터를 조회하려고만 하면 실패해버린다.




  • 머리를 싸매고 코드를 훑어보다 찾은 원인은 이렇다. 일단 본인은 Category Select를 main, sub 두개로 사용하고 있다. 이 때 main 카테고리를 눌러 옵션값을 바꾸면 그 아래의 subCategory의 선택값을 초기화시키고자 했다.

  • 이 로직을 구현하기 위해 subRef 로 subCategory를 참조한다음 그 current 값에 접근하여 내부에 정의된 메서드들 중 clearValue로 값을 초기화 시키는 로직을 구현했다.
    (참고로 따로 분기를 주었기에 저 clearValue는 현재 선택된 것이 mainCategory일때만 동작한다.)




    코드흐름을 따라 정리해본 문제의 원인은 이렇다.

    1. 처음 hooks가 실행될 때 내부에 인자로 들어오는 subRef 값은 null이다.(아직 hooks의 로직이 끝나고 props에 ref가 할당되어 전달되기 전)

    2. 핸들링 함수가 onChange 이벤트 감지로 실행되는 시점에서의 subRef는 참조를 하고 있다.(초기 렌더링 과정에서 props로 전달이 된 이후 클릭 시 실행되니깐)

    3. 이제 클릭을 하면 subCategory의 subRef 객체가 존재함으로 조건문에 따라 선택값을 지워버린다. (Select 값이 지워짐!)



  • 좀 장황하게 설명한 감이 있는데 쉽게말하면 Select 가 공통컴포넌트이고 그에 따라 개별적으로 다른 props 들을 받아 속성에 넣기 때문이다.
    현재 main, sub Select는 둘다 같은 위치에서 렌더링되고 있고, 전달하는 props는 subRef 가 null이냐 아니냐 정도의 차이만 있다. 문제는 Selector 컴포넌트의 onChange 에서 받는 Select 도 각각의 Select 의 선택값인데, mainCategory를 선택한 시점에서 subRef.current 객체가 존재하는 상태이기에 그 선택값을 지워버려서 오류가 발생한 것이다.

  • 선택값을 지웠기에 당연히 Selector 에서 이벤트인자로 넘겨주는 Select는 아무것도 없는 빈 값이 될것이고 이 때문에 select.value로 접근이 불가능했던 것이다.




  • 값이 존재할 경우만 change 메서드를 바인딩해주는 것으로 문제를 해결했다.
profile
막 발걸음을 뗀 신입

0개의 댓글

관련 채용 정보