Set을 활용한 상태 관리 최적화로 '선택된 장비가 없습니다' 오류 해결하기

가응·2025년 2월 21일
1
post-thumbnail

이런 걸 만들고 싶었는데 문제가 생겼다 …

⭐ 오류:

"선택된 장비가 없습니다" 문구가 사라지지 않는 오류‼️😢

현상 :

아이템이 선택되어 대여 신청 버튼 api에 정보가 추가되었지만,
여전히 "선택된 장비가 없습니다." 문구가 표시되는 혼란이 있었다. 😮

( selectedItems[category] || []).length > 0 조건이 예상대로 동작하지 않음 )

내가 생각했던 초기 원인은 ..🙆‍♀️

그렇다면 selectedItems의 업데이트와 렌더링이 문제가 아닐지 의심되었는데..

  1. handleItemClick에 로그를 넣어도 console에 출력되지 않고..

  2. selectedItems들은 정상적으로 업데이트 되고 있었다..

    그래서 느낌은 오는데 어떤 코드 때문인지 확신이 들지 않았다.

실제 원인은 ...!

상태 관리 방식의 문제!

: selectedItems 혹은 plan.equipment가 이전 상태를 참조하며 불변성이 유지되지 않고

-> ‼️ 렌더링이 정상적으로 이루어지지 않은 것..‼️



⭐ 해결 방법 :

  • 각 카테고리를 Set을 사용하여 중복을 처리👏

  • plan.equipment의 상태 업데이트를 불변성을 유지하면서 안전하게 변경한 것이 핵!심! 포인트 !

    • selectedItems[category]로 선택된 장비들을 관리하면서 그 상태를 반영하여 렌더링

.
.
.

  • !!! 중복 코드가 많을 때는 상태 관리가 복잡해지니까 코드가 깔끔하게 업데이트되고,
    불필요한 렌더링을 방지하는 방향으로 개선하는 것이 중요하다고 한다.

  • ( + ) Set을 사용함으로써 불필요한 중복 코드map() 호출 줄이기

불변성(Immutable State)
: React에서 상태를 직접 수정하는 것보다 ➡️ 상태를 새로 생성하는 것이 중요
- 예를 들어, setSelectedItems(prev => [...prev])처럼 이전 상태를 변경하지 않고 새로운 상태를 반환하는 방식 😮


이 중에서도

Set<string> 사용⭐이

중점적인 문제 해결에 도움을 준것 같아서, 이 부분에 대해 자세히 알아보고자 한다. >.<


Set<string>의 개념과 사용👏👏

Set : 중복된 값을 허용하지 않는 데이터 구조

  • 배열과 비슷한데 중복 허용안함
  • 메서드 :
    아이템 추가 및 삭제 - add(item), delete(item)
    / 값 확인(존재 여부) - has(item) / 모든 값 삭제 - clear()
  • 순서 없음

우리가 주목해야할 포인트는 중복 허용하지 않음 !

예를 들어 ))

이미 선택된 장비를 추가하려고 할 때, Set은 그 아이템이 이미 포함되어 있으면 추가하지 않고, 이미 존재하지 않는 경우에만 추가하게 되어있다 .

즉 ,

Set이 중복된 값들이 생기지 않도록 자연스레 관리해주는 역할 ! 을 한다 😻


set의 장점은 🤗

  • 중복 제거
  • 효율적인 추가 및 삭제
  • 불변성 유지 ( 원본 수정 대신 새롭게 복사된 개체로 값 업데이트 함 )

이라고 할 수 있겠다 !

배열을 쓰는 것보다 직관적이고 간단하게 관리하며 불변성의 오류를 줄일 수 있다 굿~~


실제 코드 비교 🐱

해결 전 코드:


const handleItemClick = (category: string, item: string) => {
  setSelectedItems((prev) => {
    const prevItems = prev[category] || [];
    const newItems = prevItems.includes(item)
      ? prevItems.filter((i) => i !== item) // 이미 선택된 경우 삭제
      : [...prevItems, item]; // 선택되지 않은 경우 추가
    return { ...prev, [category]: newItems };
  });

  // 강제 리렌더링 트리거
  setForceRender((prev) => prev + 1);
};

해결 후 코드:



const handleItemClick = (category: string, item: string) => {
  setSelectedItems((prev) => {
    const updatedCategory = new Set(prev[category] || []); // **Set**으로 기존 아이템 복사
    updatedCategory.has(item) ? updatedCategory.delete(item) : updatedCategory.add(item); // 추가 및 삭제
    return { ...prev, [category]: updatedCategory }; // **불변성을** 지키며 상태 업데이트
  });

  // 강제 리렌더링 트리거
  setForceRender((prev) => prev + 1);
};

+ 불필요한 map() 호출 제거

처음 코드에서는 plans.map()을 사용하여 모든 아이템을 순회했지만,

이렇게 해주면 중복된 아이템을 관리하는 데 Set만 사용하면 되어서 성능을 개선할 수 있다



// 중복 없이 아이템을 가져오는 방법
const uniqueItems = Array.from(
  new Set<string>(plans.flatMap((plan) => plan.equipment?.[category] || []))
);

⭐ plans.map()을 사용한 방식에서는 매번 배열을 순회해야 했지만,
Set을 사용하면
flatMap을 사용하여 중복 없이 한번에 처리할 수 있다. ⭐

.

.

코드가 복잡해질때는 간결하고 명확한 것이 최고 … ⭐ ))


⭐ 전체 문제 해결 완 ! 뭐가 나아졌나면 ..

  1. 중복 처리 최적화: Set을 사용하여 중복 아이템이 자동으로 관리되므로, 불필요한 상태 업데이트를 줄일 수 있었다.
  2. 상태 관리의 불변성 유지: 상태를 직접 수정하지 않고, 복사본을 만들어서 업데이트하므로 React에서 예상치 못한 동작을 방지할 수 있었습니다.
  3. 성능 최적화: map() 호출을 줄이고, Set을 사용하여 아이템을 효율적으로 관리함으로써 렌더링 성능을 개선할 수 있었습니다.👍

⭐ 새롭게 배운점

1. 불변성의 중요성…😉 ( setState 공부 이후 또 다시 느낀 .. )

React에서 상태를 직접 변경하지 않고, 상태의 복사본을 만들어 변경하는 방식

렌더링에도 영향을 미쳐서 매우매우 중요한 것 같다

2. Set의 효율성

중복 코드가 많아지고 상태 관리가 복잡해질 때, Set의 사용은 중복을 자동으로 제거해주니까 매우 효율적이다 .. !>!>

3. 상태 업데이트 최적화

상태 업데이트를 최적화하려면..!

불필요한 map() 호출을 피하고, Set과 같은 자료구조를 사용해서 성능 개선 해보기 … !


끝 ‼️

0개의 댓글