🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Provider 기본 개념 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 30. · 16 Views

Provider 기본 개념 완벽 가이드

Flutter의 상태 관리 라이브러리인 Provider의 기본 개념을 초급 개발자를 위해 쉽게 설명합니다. Provider의 선언부터 생명주기, autoDispose까지 실무에 바로 적용할 수 있는 핵심 개념을 다룹니다.


목차

  1. Provider란_무엇인가
  2. Provider_선언하기
  3. 글로벌_상태_vs_로컬_상태
  4. Provider의_생명주기
  5. autoDispose와_keepAlive
  6. Provider_네이밍_컨벤션

1. Provider란 무엇인가

입사 첫 주, 김개발 씨는 선배가 작성한 Flutter 코드를 보다가 고개를 갸우뚱했습니다. "ref.watch?

Provider? 이게 다 뭐지?" 분명 상태 관리가 중요하다고 들었는데, 막상 코드를 보니 낯선 용어들이 쏟아졌습니다.

Provider는 Flutter에서 상태를 관리하고 공유하기 위한 도구입니다. 마치 회사의 공용 냉장고처럼, 여러 위젯이 함께 사용해야 하는 데이터를 한 곳에 보관하고 필요할 때 꺼내 쓸 수 있게 해줍니다.

Riverpod은 Provider의 개념을 더욱 발전시킨 현대적인 상태 관리 라이브러리입니다.

다음 코드를 살펴봅시다.

// Provider는 데이터를 제공하는 컨테이너입니다
final greetingProvider = Provider<String>((ref) {
  // 이 함수가 반환하는 값이 Provider가 제공하는 데이터
  return '안녕하세요, Flutter 개발자님!';
});

// 위젯에서 Provider의 값을 사용하는 방법
class GreetingWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // ref.watch로 Provider의 값을 구독합니다
    final greeting = ref.watch(greetingProvider);
    return Text(greeting);
  }
}

김개발 씨는 입사 첫 주를 맞이한 신입 개발자입니다. 회사에서 진행 중인 Flutter 프로젝트에 투입되었는데, 선배들이 작성한 코드에는 낯선 키워드들이 가득했습니다.

Provider, ref, watch... 대체 이것들이 무엇일까요?

선배 개발자 박시니어 씨가 커피 한 잔을 건네며 설명을 시작했습니다. "Provider가 뭔지 알려면, 먼저 왜 필요한지부터 이해해야 해요." Flutter로 앱을 만들다 보면 여러 화면에서 같은 데이터를 사용해야 하는 상황이 자주 발생합니다.

예를 들어 사용자의 로그인 정보는 홈 화면, 설정 화면, 프로필 화면 등 여러 곳에서 필요합니다. 이 데이터를 각 화면마다 따로 관리한다면 어떻게 될까요?

박시니어 씨는 비유를 들어 설명했습니다. "회사 공용 냉장고를 생각해 봐요.

모든 직원이 각자 책상에 미니 냉장고를 두면 공간 낭비에 전기 요금 폭탄이죠. 대신 공용 냉장고 하나를 두고 모두가 필요할 때 꺼내 쓰잖아요.

Provider가 바로 그 공용 냉장고 역할을 합니다." Provider는 데이터를 담는 컨테이너입니다. 이 컨테이너에 데이터를 넣어두면, 앱의 어느 위젯에서든 그 데이터에 접근할 수 있습니다.

더 좋은 점은 데이터가 변경되면 그 데이터를 사용하는 모든 위젯이 자동으로 업데이트된다는 것입니다. 위 코드를 살펴보겠습니다.

greetingProvider는 문자열 데이터를 제공하는 Provider입니다. Provider를 선언할 때는 함수를 전달하는데, 이 함수가 반환하는 값이 바로 Provider가 제공하는 데이터가 됩니다.

ConsumerWidget은 Provider의 데이터를 사용할 수 있는 특별한 위젯입니다. build 메서드에서 ref 파라미터를 받는데, 이 ref를 통해 Provider에 접근합니다.

ref.watch를 호출하면 해당 Provider의 값을 가져오고, 값이 변경될 때마다 위젯을 다시 빌드합니다. 실제 현업에서는 사용자 인증 상태, 장바구니 목록, 앱 설정 등을 Provider로 관리합니다.

한 곳에서 데이터를 관리하니 코드가 깔끔해지고, 데이터 흐름을 파악하기도 쉬워집니다. 김개발 씨가 고개를 끄덕였습니다.

"아, 그러니까 Provider는 데이터를 공유하는 창고 같은 거군요!" 박시니어 씨가 미소 지었습니다. "정확해요.

이제 Provider를 선언하는 방법을 더 자세히 알아볼까요?"

실전 팁

💡 - Provider는 전역 변수처럼 파일 최상위에 선언하는 것이 일반적입니다

  • ref.watch는 값의 변화를 구독하고, ref.read는 일회성 읽기에 사용합니다

2. Provider 선언하기

김개발 씨는 Provider의 개념을 이해했지만, 막상 코드를 작성하려니 막막했습니다. "Provider를 어떻게 선언하지?

StateProvider는 뭐고, FutureProvider는 또 뭐지?" 화면에는 여러 종류의 Provider가 있었습니다.

Provider 선언은 데이터의 성격에 따라 적절한 타입을 선택하는 것이 핵심입니다. 변하지 않는 값은 Provider, 변하는 값은 StateProvider, 비동기 데이터는 FutureProvider를 사용합니다.

마치 물건의 종류에 따라 다른 보관함을 사용하는 것과 같습니다.

다음 코드를 살펴봅시다.

// 1. 기본 Provider - 변하지 않는 값
final appNameProvider = Provider<String>((ref) {
  return '내 멋진 앱';
});

// 2. StateProvider - 변경 가능한 단순 상태
final counterProvider = StateProvider<int>((ref) {
  return 0; // 초기값
});

// 3. FutureProvider - 비동기 데이터
final userProvider = FutureProvider<User>((ref) async {
  final response = await api.fetchUser();
  return User.fromJson(response);
});

// 4. StateNotifierProvider - 복잡한 상태 로직
final todoListProvider = StateNotifierProvider<TodoNotifier, List<Todo>>((ref) {
  return TodoNotifier();
});

박시니어 씨는 화이트보드에 그림을 그리기 시작했습니다. "Provider를 선언하는 건 마치 물건에 맞는 보관함을 고르는 것과 같아요." 우체국에 가면 소포 크기에 따라 다른 박스를 사용하죠?

작은 물건은 소형 박스에, 큰 물건은 대형 박스에 넣습니다. Provider도 마찬가지입니다.

데이터의 성격에 따라 적절한 Provider 타입을 선택해야 합니다. 가장 기본이 되는 것은 Provider입니다.

이름도 그냥 Provider죠. 이것은 한 번 정해지면 변하지 않는 값을 담습니다.

앱 이름, 환경 설정 상수, 계산된 파생 값 등이 여기에 해당합니다. 위 코드의 appNameProvider처럼 단순히 값을 반환하기만 하면 됩니다.

그런데 카운터 앱처럼 값이 변해야 하는 경우는 어떨까요? 이때는 StateProvider를 사용합니다.

StateProvider는 상태를 읽을 수도 있고, 변경할 수도 있습니다. 버튼을 누르면 숫자가 올라가는 것처럼 간단한 상태 변경에 적합합니다.

서버에서 데이터를 가져와야 하는 경우도 있습니다. 사용자 정보를 API로 요청하는 상황을 생각해 보세요.

네트워크 요청은 시간이 걸리니 비동기로 처리해야 합니다. 이런 경우 FutureProvider를 사용합니다.

async/await를 자연스럽게 사용할 수 있고, 로딩 상태와 에러 처리도 자동으로 관리됩니다. 마지막으로 StateNotifierProvider가 있습니다.

장바구니처럼 여러 동작(추가, 삭제, 수정)이 필요한 복잡한 상태에 적합합니다. 상태 변경 로직을 별도의 클래스로 분리하여 관리할 수 있어 코드가 깔끔해집니다.

김개발 씨가 질문했습니다. "그럼 어떤 Provider를 써야 할지 어떻게 판단하나요?" 박시니어 씨는 간단한 기준을 알려주었습니다.

값이 변하지 않으면 Provider, 단순한 값이 변하면 StateProvider, 비동기 작업이면 FutureProvider, 복잡한 로직이면 StateNotifierProvider입니다. 실무에서는 이 네 가지를 상황에 맞게 조합하여 사용합니다.

처음에는 StateProvider로 시작했다가 로직이 복잡해지면 StateNotifierProvider로 변경하는 경우도 많습니다. 중요한 것은 현재 상황에 가장 적합한 것을 선택하는 것입니다.

김개발 씨는 고개를 끄덕였습니다. "데이터 성격에 맞는 Provider를 고르면 되는 거군요.

생각보다 단순하네요!"

실전 팁

💡 - 처음에는 StateProvider로 시작하고, 복잡해지면 StateNotifierProvider로 전환하세요

  • FutureProvider는 자동으로 AsyncValue를 반환하여 로딩/에러 상태를 처리합니다

3. 글로벌 상태 vs 로컬 상태

코드 리뷰 시간, 박시니어 씨가 김개발 씨의 코드를 보며 물었습니다. "이 상태, 꼭 글로벌이어야 해요?

이 화면에서만 쓰이는 것 같은데..." 김개발 씨는 모든 상태를 Provider로 만들었는데, 무엇이 문제인 걸까요?

글로벌 상태는 여러 화면에서 공유하는 데이터이고, 로컬 상태는 특정 위젯 내에서만 사용하는 데이터입니다. 모든 것을 글로벌로 만들면 앱이 복잡해지고, 모든 것을 로컬로 만들면 데이터 공유가 어렵습니다.

적절한 균형이 중요합니다.

다음 코드를 살펴봅시다.

// 글로벌 상태 - 여러 화면에서 공유
final userProvider = StateProvider<User?>((ref) => null);
final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) {
  return CartNotifier();
});

// 로컬 상태 - 특정 위젯 내에서만 사용
class SearchScreen extends ConsumerStatefulWidget {
  @override
  ConsumerState<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends ConsumerState<SearchScreen> {
  // 이 화면에서만 쓰이는 검색어는 로컬 상태로 관리
  String _searchQuery = '';
  bool _isExpanded = false;

  @override
  Widget build(BuildContext context) {
    return TextField(onChanged: (value) => setState(() => _searchQuery = value));
  }
}

박시니어 씨는 김개발 씨를 회의실로 데려갔습니다. "상태 관리에서 가장 중요한 건 어디에 상태를 둘 것인가예요." 비유를 들어볼까요?

회사에는 공용 문서와 개인 문서가 있습니다. 팀 전체가 봐야 하는 기획서는 공유 드라이브에 올리지만, 자신만의 메모는 개인 폴더에 저장하죠.

모든 문서를 공유 드라이브에 올리면 어떻게 될까요? 금방 지저분해지고 필요한 문서를 찾기 어려워집니다.

글로벌 상태는 공유 드라이브와 같습니다. 사용자 인증 정보, 장바구니 목록, 앱 테마 설정 등 여러 화면에서 접근해야 하는 데이터가 여기에 속합니다.

이런 데이터는 Provider로 선언하여 앱 전체에서 접근할 수 있게 합니다. 반면 로컬 상태는 개인 폴더와 같습니다.

텍스트 필드의 입력값, 버튼의 호버 상태, 드롭다운 메뉴의 열림/닫힘 상태 등 특정 위젯 내에서만 의미 있는 데이터입니다. 이런 데이터까지 전부 Provider로 만들면 코드가 복잡해지고 관리가 어려워집니다.

김개발 씨가 물었습니다. "그럼 기준이 뭐예요?

어떤 상태를 글로벌로 해야 할지 헷갈려요." 박시니어 씨는 세 가지 질문을 던졌습니다. 첫째, 이 데이터가 다른 화면에서도 필요한가요?

둘째, 앱을 다시 실행해도 유지되어야 하나요? 셋째, 다른 상태와 연결되어 있나요?

하나라도 해당되면 글로벌을, 모두 아니라면 로컬을 선택하면 됩니다. 위 코드를 보면, 사용자 정보와 장바구니는 여러 화면에서 필요하므로 글로벌 Provider로 선언했습니다.

반면 검색어 입력값과 UI 확장 상태는 해당 화면에서만 필요하므로 setState를 사용하는 로컬 상태로 관리합니다. 초보 개발자들이 흔히 하는 실수는 모든 것을 Provider로 만드는 것입니다.

"Provider를 쓰면 뭔가 더 있어 보이잖아요?" 하지만 이렇게 하면 불필요한 복잡성이 생기고, 오히려 성능 문제가 발생할 수 있습니다. 김개발 씨는 자신의 코드를 다시 살펴봤습니다.

검색 화면의 필터 옵션들이 전부 Provider로 되어 있었는데, 사실 그 화면에서만 쓰이는 것들이었습니다. "이건 로컬 상태로 바꿔야겠네요!" 박시니어 씨가 웃으며 말했습니다.

"그래요. 적재적소가 핵심이에요.

필요한 곳에 필요한 만큼만 사용하세요."

실전 팁

💡 - 상태를 어디에 둘지 고민될 때는 먼저 로컬로 시작하고, 공유가 필요해지면 글로벌로 올리세요

  • ConsumerStatefulWidget을 사용하면 Provider와 로컬 상태를 함께 사용할 수 있습니다

4. Provider의 생명주기

김개발 씨가 앱을 테스트하다가 이상한 현상을 발견했습니다. 화면을 왔다 갔다 할 때마다 API가 계속 호출되는 것이었습니다.

"왜 이러지? 데이터가 있으면 다시 안 불러와야 하는 거 아닌가?" Provider가 언제 생성되고 언제 사라지는지 이해해야 할 때입니다.

Provider의 생명주기는 언제 데이터가 생성되고, 유지되고, 파괴되는지를 결정합니다. 기본적으로 Provider는 처음 읽힐 때 생성되고, 더 이상 사용되지 않으면 파괴됩니다.

이 동작을 이해하면 불필요한 API 호출이나 메모리 낭비를 방지할 수 있습니다.

다음 코드를 살펴봅시다.

// Provider는 처음 watch/read될 때 생성됩니다
final dataProvider = FutureProvider<List<Item>>((ref) async {
  print('Provider 생성: API 호출 시작');
  final data = await api.fetchItems();
  print('Provider 생성 완료: 데이터 로드됨');
  return data;
});

// 생명주기 콜백 활용
final connectionProvider = Provider<WebSocket>((ref) {
  print('WebSocket 연결 생성');
  final socket = WebSocket.connect('ws://example.com');

  // Provider가 파괴될 때 실행되는 정리 로직
  ref.onDispose(() {
    print('WebSocket 연결 종료');
    socket.close();
  });

  return socket;
});

박시니어 씨는 화이트보드에 생명주기 다이어그램을 그렸습니다. "Provider의 생명주기를 이해하면 많은 버그를 예방할 수 있어요." 사람의 일생을 생각해 봅시다.

태어나고, 살다가, 죽습니다. Provider도 비슷합니다.

생성되고, 유지되다가, 파괴됩니다. 중요한 건 이 각 단계가 언제 일어나는지 아는 것입니다.

Provider는 지연 생성(lazy initialization) 방식을 사용합니다. 선언한다고 바로 만들어지는 게 아니라, 누군가 ref.watch나 ref.read로 처음 접근할 때 비로소 생성됩니다.

마치 도서관 책이 빌려갈 때까지 서가에 조용히 있는 것과 같습니다. 김개발 씨가 물었습니다.

"그럼 한 번 생성된 Provider는 계속 유지되나요?" 좋은 질문입니다. 기본적으로 Provider는 누군가 구독하고 있는 한 살아 있습니다.

화면 A에서 userProvider를 watch하고 있다면, 화면 A가 존재하는 동안 userProvider도 유지됩니다. 하지만 화면 A가 사라지고 더 이상 아무도 구독하지 않으면, Provider는 파괴됩니다.

파괴될 때 정리해야 할 작업이 있을 수 있습니다. 웹소켓 연결을 끊거나, 스트림 구독을 취소하거나, 타이머를 정지하는 등의 작업입니다.

이때 ref.onDispose를 사용합니다. onDispose에 등록한 콜백은 Provider가 파괴될 때 자동으로 실행됩니다.

위 코드의 connectionProvider를 보세요. 웹소켓 연결을 생성하고, onDispose에서 연결을 종료하는 로직을 등록했습니다.

이렇게 하면 Provider가 더 이상 필요 없을 때 자원이 제대로 정리됩니다. 김개발 씨의 문제로 돌아가 봅시다.

API가 계속 호출되었던 이유는 화면을 떠날 때마다 Provider가 파괴되고, 다시 돌아올 때 새로 생성되었기 때문입니다. 데이터를 유지하고 싶다면 Provider가 파괴되지 않도록 해야 합니다.

박시니어 씨가 덧붙였습니다. "다음에 배울 autoDispose와 keepAlive가 바로 이 문제를 해결하는 방법이에요." 김개발 씨는 메모장에 적었습니다.

"Provider 생명주기: 생성 시점과 파괴 시점을 항상 의식하자!"

실전 팁

💡 - ref.onDispose는 리소스 정리에 필수입니다. 스트림, 웹소켓, 타이머 등은 반드시 정리하세요

  • Provider가 예상보다 자주 재생성된다면 생명주기를 점검해 보세요

5. autoDispose와 keepAlive

박시니어 씨가 코드 리뷰에서 지적했습니다. "여기 autoDispose 안 썼네요?

메모리 누수 날 수 있어요." 김개발 씨는 autoDispose라는 키워드를 처음 들어봤습니다. Provider에 붙이는 이 수정자가 왜 중요한 걸까요?

autoDispose는 Provider가 더 이상 사용되지 않을 때 자동으로 파괴되도록 하는 수정자입니다. keepAlive는 반대로 특정 조건에서 Provider를 유지하도록 합니다.

이 둘을 적절히 조합하면 메모리를 효율적으로 관리하면서도 필요한 데이터는 유지할 수 있습니다.

다음 코드를 살펴봅시다.

// autoDispose: 화면을 떠나면 자동으로 파괴
final searchResultProvider = FutureProvider.autoDispose<List<Item>>((ref) async {
  final query = ref.watch(searchQueryProvider);
  return await api.search(query);
});

// keepAlive: 조건부로 상태 유지
final userDataProvider = FutureProvider.autoDispose<User>((ref) async {
  // 데이터 로드 성공 시 Provider 유지
  final link = ref.keepAlive();

  try {
    final user = await api.fetchUser();
    return user;
  } catch (e) {
    // 에러 발생 시 캐시하지 않음 (다시 시도 가능하도록)
    link.close();
    rethrow;
  }
});

// ref.invalidate로 수동 갱신
ref.invalidate(userDataProvider); // 강제로 다시 로드

박시니어 씨는 스마트폰 앱을 예로 들었습니다. "우리가 앱을 쓸 때 화면을 계속 이동하잖아요.

방문한 모든 화면의 데이터가 메모리에 쌓이면 어떻게 될까요?" 맞습니다. 앱이 점점 느려지고 결국 크래시가 날 수 있습니다.

이것이 바로 autoDispose가 필요한 이유입니다. autoDispose는 Provider에 붙이는 수정자입니다.

이 수정자를 붙이면 해당 Provider를 구독하는 위젯이 모두 사라졌을 때 Provider도 함께 파괴됩니다. 마치 손님이 모두 떠난 후 식당 불을 끄는 것과 같습니다.

기본 Provider는 한 번 생성되면 앱이 종료될 때까지 유지됩니다. 사용자 인증 정보처럼 계속 필요한 데이터는 이게 맞습니다.

하지만 검색 결과처럼 일시적인 데이터는 어떨까요? 검색 화면을 떠나면 더 이상 필요 없는 데이터입니다.

이런 경우 autoDispose를 사용합니다. 김개발 씨가 의문을 제기했습니다.

"그런데 autoDispose를 쓰면 API가 매번 호출되지 않나요? 이전에 문제였던 것처럼요." 좋은 지적입니다.

여기서 keepAlive가 등장합니다. ref.keepAlive()를 호출하면 autoDispose의 자동 파괴를 막을 수 있습니다.

위 코드를 보세요. 데이터 로드에 성공하면 keepAlive를 유지하고, 실패하면 link.close()로 해제합니다.

이 패턴의 장점은 뭘까요? 성공한 데이터는 캐시되어 다시 화면에 돌아와도 API를 호출하지 않습니다.

하지만 에러가 발생했던 경우는 캐시되지 않아 다시 시도할 수 있습니다. 실무에서 매우 유용한 패턴입니다.

데이터를 강제로 새로고침하고 싶을 때는 ref.invalidate를 사용합니다. invalidate를 호출하면 Provider가 파괴되고, 다음에 접근할 때 새로 생성됩니다.

풀투리프레시(당겨서 새로고침) 기능을 구현할 때 자주 사용합니다. 박시니어 씨가 정리했습니다.

"autoDispose는 기본으로 붙이세요. 그리고 캐시가 필요한 경우에만 keepAlive를 조건부로 사용하면 됩니다." 김개발 씨는 자신의 코드를 수정하기 시작했습니다.

대부분의 FutureProvider에 autoDispose를 추가하고, 필요한 곳에만 keepAlive 패턴을 적용했습니다.

실전 팁

💡 - 새 프로젝트에서는 autoDispose를 기본으로 사용하는 것이 권장됩니다

  • ref.invalidate는 풀투리프레시, 로그아웃 후 데이터 초기화 등에 활용하세요

6. Provider 네이밍 컨벤션

프로젝트가 커지면서 Provider의 수가 수십 개로 늘어났습니다. userProvider, userData, fetchUser, userState...

팀원마다 이름 짓는 방식이 달랐고, 코드를 읽기가 점점 어려워졌습니다. 박시니어 씨가 팀 회의를 소집했습니다.

네이밍 컨벤션은 코드의 가독성과 유지보수성을 크게 높입니다. Provider 이름은 무엇을 제공하는지 명확히 드러내야 하며, 팀 전체가 일관된 규칙을 따라야 합니다.

좋은 이름은 코드를 읽는 사람에게 Provider의 역할을 즉시 알려줍니다.

다음 코드를 살펴봅시다.

// 권장: 명확하고 일관된 네이밍
final currentUserProvider = StateProvider<User?>((ref) => null);
final productListProvider = FutureProvider<List<Product>>((ref) async => []);
final cartItemsProvider = StateNotifierProvider<CartNotifier, List<CartItem>>(
  (ref) => CartNotifier(),
);

// 비권장: 모호하거나 불일치하는 네이밍
final user = StateProvider<User?>((ref) => null); // Provider인지 불명확
final getProducts = FutureProvider((ref) async => []); // 동사는 피하기
final CART_ITEMS = StateNotifierProvider((ref) => CartNotifier()); // 대문자 지양

// 파일 구조 예시
// lib/providers/
//   auth_provider.dart      - 인증 관련 Provider
//   product_provider.dart   - 상품 관련 Provider
//   cart_provider.dart      - 장바구니 관련 Provider

팀 회의실에서 박시니어 씨가 말문을 열었습니다. "여러분, 코드에서 이름이 얼마나 중요한지 아시죠?" 프로그래밍에서 이름 짓기는 가장 어려운 일 중 하나입니다.

하지만 좋은 이름은 코드를 문서화하는 것과 같습니다. 이름만 보고도 무슨 역할을 하는지 알 수 있다면, 주석 없이도 코드를 이해할 수 있습니다.

Provider 네이밍의 첫 번째 원칙은 Provider 접미사를 붙이는 것입니다. currentUserProvider, productListProvider처럼 말이죠.

이렇게 하면 변수가 Provider라는 것을 즉시 알 수 있습니다. 그냥 user라고 하면 User 객체인지, Provider인지 혼란스럽습니다.

두 번째 원칙은 무엇을 제공하는지 명사로 표현하는 것입니다. fetchUser나 getProducts처럼 동사로 시작하는 것은 피합니다.

Provider는 데이터를 제공하는 컨테이너이지, 동작이 아닙니다. 대신 userData, products처럼 명사를 사용하세요.

세 번째 원칙은 **카멜케이스(camelCase)**를 사용하는 것입니다. Dart의 변수 네이밍 규칙이기도 합니다.

SCREAMING_SNAKE_CASE는 상수에만 사용하고, Provider에는 적합하지 않습니다. 김개발 씨가 질문했습니다.

"Provider가 많아지면 어떻게 관리하나요?" 박시니어 씨는 파일 구조를 보여주었습니다. Provider는 도메인별로 파일을 분리하는 것이 좋습니다.

auth_provider.dart에는 인증 관련 Provider들을, product_provider.dart에는 상품 관련 Provider들을 모아둡니다. 이렇게 하면 관련 코드를 찾기 쉽고, 코드 리뷰도 수월해집니다.

또 하나 중요한 것은 일관성입니다. 팀에서 한 번 규칙을 정하면 모두가 따라야 합니다.

어떤 사람은 Provider를 붙이고, 어떤 사람은 안 붙이면 코드가 혼란스러워집니다. 규칙 자체보다 일관되게 지키는 것이 더 중요합니다.

회의가 끝나고 팀은 네이밍 가이드 문서를 만들었습니다. Provider는 반드시 Provider 접미사를 붙이고, 제공하는 데이터를 명사로 표현하고, 파일은 도메인별로 분리한다.

단순한 규칙이지만, 이것만 지켜도 코드의 품질이 크게 올라갔습니다. 김개발 씨는 기존 코드를 리팩토링하면서 좋은 이름의 가치를 실감했습니다.

"이름만 바꿨을 뿐인데 코드가 훨씬 읽기 쉬워졌어요!"

실전 팁

💡 - 팀 네이밍 가이드 문서를 만들고 온보딩 시 공유하세요

  • IDE의 린트 규칙을 활용하면 네이밍 컨벤션을 자동으로 강제할 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Flutter#Provider#Riverpod#StateManagement#autoDispose#Flutter,State Management

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스