10. 매장 리스트 만들기

2025. 3. 18. 09:37현 프로젝트 시작단계

728x90

일단 현 상황은 

마커 수만큼 바텀시트에 마커 개수와 정보를 띄우게 만들었다.

 

만약 필터를 만들려는 상황이면 

어떻게 필터링을 해야될까 고민해야 된다.

그래서 이론부터 간략하게 설명하려고 한다.

 

 

 

현재 내 데이터

 

지금 데이터는 Supabase에서 가져오고 있고,

fetchModirDataInBounds는 지도 bounds에 맞는 데이터를 필터링해서 가져온다.

  • 이미 서버에서 좌표 기반으로 1차 필터링이 된 상태
  • 이 데이터를 클라이언트(Dart) 쪽에서 추가로 clothesgender: 남성에 맞춰서 필터링하고 싶음

 

 

필터링 방향 고민

 

clothesgender: 남성을 필터링하려면 두 가지 접근법이 떠올라:

  1. 서버에서 필터링: Supabase 쿼리에서 조건을 추가해서 아예 "남성" 데이터만 가져오게 하는 방법.
  2. 클라이언트에서 필터링: 지금처럼 데이터를 다 가져온 뒤에 Dart 코드에서 조건에 맞는 데이터만 골라내는 방법.

 

뭐가 더 맞을지 지금부터 고민을 해보겠다.

 

기준으로 볼 요소들

  1. 성능 (속도): 사용자 입장에서 필터 적용이 빠르게 반영되는 게 중요할까?
  2. 데이터 크기: 마커 데이터가 얼마나 많을지, 그리고 지도 bounds 안에 보통 몇 개 정도의 매장이 포함될지 생각해보자.
  3. 사용성: 필터를 자주 바꾸거나 여러 조건(성별, 스타일 등)을 조합할 가능성이 높은가?
  4. 개발 편의성: 네가 구현하고 유지보수하기 쉬운 방법이 뭘까?

서버에서 필터링 vs 클라이언트에서 필터링

서버에서 필터링 (Supabase 쿼리 수정)

  • 장점:
    • 서버에서 필요한 데이터만 내려주니까 네트워크 요청이 효율적이고, 클라이언트 부하가 줄어.
    • 데이터가 많아도 클라이언트는 가볍게 유지될 가능성이 높아.
  • 단점:
    • 필터 조건(예: "남성" → "여성"으로 변경)이 바뀔 때마다 Supabase에 새 요청을 보내야 해서, 네트워크 딜레이가 생길 수 있어.
    • 여러 필터(성별 + 스타일 + 브랜드)를 조합하려면 쿼리가 복잡해질 수 있음.
  • 적합한 경우:
    • 데이터가 많고(수백 개 이상), 필터 변경이 자주 일어나지 않을 때.
    • 서버 성능이 좋아서 요청 처리 속도가 빠를 때.

클라이언트에서 필터링 (Dart에서 처리)

  • 장점:
    • 한 번 데이터를 가져오면 로컬에서 필터링하니까, 필터를 바꿀 때마다 서버 요청을 안 해도 돼서 반응이 즉각적일 수 있어.
    • 여러 필터 조건을 조합하거나 해제하는 게 자유롭고 유연함.
  • 단점:
    • bounds 안의 데이터가 많아지면(예: 1000개 이상), 클라이언트에서 필터링하는 데 시간이 걸릴 수 있음.
    • 메모리 사용량이 늘어날 수 있어.
  • 적합한 경우:
    • 데이터가 적당히 적거나(수십~수백 개), 사용자가 필터를 자주 바꿀 가능성이 높을 때.
    • 네트워크 요청을 줄이고 UI 반응성을 높이고 싶을 때.

 

 

여기서 나는 클라이언트에서 필터링을 선택하였다. 

일단 애초에 사용자가 보는 화면에서 만 마커가뜨게 필터링을 했기 때문에 한 번에 1000개 이상의 매장이 나올 일이 없음

최대 많아도 200~300개임 근데 심지어 지도에서도 확대 zoom이 10 레벨부터 지도 마커 업데이트 기능을 넣었으니

더더욱 100개 이상은 나오기 힘들거라 판단 

그렇다면 나는 여러 필터 쓰는데 문제가 없고 반응 즉각적인 클라이언트 방식을 선택했음.

 

 

 

그럼 클라이언트 방법중 어떠한 방법으로 ?

 

 

자신의 필터를 눌렀을때 나오는 바텀시트에 

String? selectedType;

변수를 하나만들어주고 

 

 

버튼을 클릭해서 적용을 하면 

typeButton('편집샵'), 
SizedBox(width: 16.w),
typeButton('구제'),

 

현재  매장이라고 되어있던곳이 고른 버튼 타입에 따라 텍스트가 변경되게 만들었습니다.

밑에 코드는 매장버튼을 클릭했을때 로직입니다.

onTap: () async {
  final selectedGender =
      await GenderBottomSheet
          .show(
              context);
  setState(() {
    filters["gender"] =
        selectedGender;
    if (selectedGender !=
            null ||
        filters["type"] !=
            null) {
      context
          .read<
              DataViewModel>()
          .fetchFilteredDataInBounds(
            context
                .read<
                    DataViewModel>()
                .currentBounds!,
            filters[
                "gender"],
            filters[
                "type"],
          );
    } else {
      context
          .read<
              DataViewModel>()
          .fetchDataInBounds(
            context
                .read<
                    DataViewModel>()
                .currentBounds!,
          );
    }
  });
},

 

 

뷰단에 필터로직

void applyFilters() {
  setState(() {
    filteredData = dataProvider.dataList.where((modir) {
      return filters.entries.every((entry) {
        final key = entry.key;
        final value = entry.value;
        if (value == null) return true; // 필터 없으면 통과
        switch (key) {
          case "gender":
            return modir.clothesgender == value;
          case "type": // type 필터 추가
            return modir.type == value;
          case "brand":
            return true; // 아직 구현 안 됨
          case "store":
            return true; // 아직 구현 안 됨
          default:
            return true; // 알 수 없는 키는 통과
        }
      });
    }).toList();
  });
}

 

 

 

서버에서 불러오는 로직은

현재 사용자가 바운딩 되고있는 데이터를 불러오게 하였고 

거기에서 서버에서 불러온 type 값과 매장안에있는 필터에 저장된 편집샵이 동일할때 

그 리스트를 불러오게 만들었습니다. 

 

// 특정 필터에 맞는 데이터만 필터링하여 불러오기
Future<void> fetchFilteredDataInBounds(NLatLngBounds bounds, String? gender, String? type) async {
  print('Fetching filtered data in bounds: gender = $gender, type = $type');
  isLoading = true;
  errorMessage = null;
  notifyListeners();

  try {
    // 원본 데이터 불러오기
    await fetchDataInBounds(bounds);

    // 다중 필터링 적용
    dataList = dataList.where((modir) {
      bool matchesGender = gender == null || modir.clothesgender == gender;
      bool matchesType = type == null || modir.type == type;
      return matchesGender && matchesType; // 두 조건 모두 만족해야 함
    }).toList();

    print('Filtered data count: ${dataList.length}');
  } catch (e) {
    errorMessage = e.toString();
    print('Error in fetching filtered data: $errorMessage');
  } finally {
    isLoading = false;
    notifyListeners();
  }
}

 

 

자그럼 이제 로직을 보면

 

지도에서 매장 3개가떳다

그리고 성별에서 남여공용을 고르면? 짠 남여공용만뜬다.~

728x90