🤖

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

⚠️

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

이미지 로딩 중...

ref.watch와 ref.read 완벽 이해 - 슬라이드 1/7
A

AI Generated

2025. 11. 30. · 14 Views

ref.watch와 ref.read 완벽 이해

Flutter Riverpod에서 가장 중요한 개념인 Ref 객체와 watch, read, listen 메서드의 차이점을 실무 예제와 함께 쉽게 설명합니다. 언제 어떤 메서드를 사용해야 하는지 명확하게 이해할 수 있습니다.


목차

  1. Ref 객체 이해하기
  2. ref.watch() - 반응형 구독
  3. ref.read() - 일회성 읽기
  4. ref.listen() - 사이드 이펙트
  5. 언제 watch를 쓰고 언제 read를 쓸까?
  6. 흔한 실수와 해결법

1. Ref 객체 이해하기

입사 첫 주, 김개발 씨는 선배가 작성한 Riverpod 코드를 보며 고개를 갸웃거렸습니다. "ref라는 게 도대체 뭐지?

왜 이렇게 자주 등장하는 거야?" 마치 모든 코드의 중심에 ref가 있는 것처럼 보였습니다.

Ref는 Riverpod에서 Provider들을 연결해주는 핵심 객체입니다. 마치 도서관의 사서가 모든 책의 위치를 알고 원하는 책을 찾아주는 것처럼, Ref는 앱 내 모든 Provider에 접근할 수 있는 통로 역할을 합니다.

이 객체를 통해 다른 Provider의 값을 읽고, 구독하고, 변화를 감지할 수 있습니다.

다음 코드를 살펴봅시다.

// Ref 객체는 Provider 내부에서 자동으로 제공됩니다
final userProvider = Provider<User>((ref) {
  // ref를 통해 다른 Provider에 접근
  final authState = ref.watch(authProvider);
  final apiClient = ref.read(apiClientProvider);

  // ref.onDispose로 정리 작업 등록
  ref.onDispose(() {
    print('Provider가 더 이상 사용되지 않습니다');
  });

  return User(
    isLoggedIn: authState.isAuthenticated,
    client: apiClient,
  );
});

김개발 씨는 입사 첫 주를 보내고 있었습니다. 회사의 Flutter 프로젝트는 상태 관리로 Riverpod을 사용하고 있었는데, 코드 곳곳에서 ref라는 낯선 존재가 눈에 띄었습니다.

"선배, 이 ref가 정확히 뭔가요?" 김개발 씨가 박시니어 씨에게 조심스럽게 물었습니다. 박시니어 씨는 잠시 생각하더니 비유를 들어 설명하기 시작했습니다.

"회사 건물의 안내 데스크를 생각해봐. 방문객이 어느 부서를 찾든, 안내 데스크에서 위치를 알려주잖아.

Ref도 마찬가지야. 앱 내 어떤 Provider든 Ref를 통하면 접근할 수 있어." 이 비유가 김개발 씨의 머릿속에 확실히 자리 잡았습니다.

Ref는 결국 Provider들의 세계를 연결해주는 중앙 관리자인 셈입니다. Riverpod 이전의 상태 관리를 떠올려 봅시다.

각 상태가 서로를 참조하려면 복잡한 의존성 주입이 필요했습니다. 어떤 서비스가 다른 서비스를 필요로 하면, 생성자에 일일이 전달하거나 전역 인스턴스를 만들어야 했습니다.

Ref는 이런 문제를 우아하게 해결합니다. Provider를 정의할 때 첫 번째 인자로 ref가 자동으로 전달되고, 이 ref를 통해 필요한 다른 Provider에 자유롭게 접근할 수 있습니다.

마치 안내 데스크에 "마케팅팀 어디 있나요?"라고 물으면 바로 알려주는 것처럼요. 위 코드를 살펴보면, userProvider 내부에서 ref를 사용해 authProviderapiClientProvider에 접근하고 있습니다.

별도의 설정이나 주입 없이도 필요한 의존성을 바로 가져올 수 있는 것입니다. 특히 주목할 점은 ref.onDispose입니다.

Provider가 더 이상 사용되지 않을 때 실행될 정리 작업을 등록할 수 있습니다. 스트림 구독 해제나 컨트롤러 정리 같은 작업에 유용합니다.

박시니어 씨가 덧붙였습니다. "Ref의 진짜 힘은 단순히 값을 가져오는 게 아니야.

watch, read, listen 같은 메서드를 통해 상태 변화에 어떻게 반응할지 세밀하게 제어할 수 있다는 거지." 김개발 씨는 고개를 끄덕였습니다. Ref가 단순한 접근자가 아니라, Provider 간의 관계와 생명주기를 관리하는 핵심 도구라는 것을 이해하기 시작했습니다.

실전 팁

💡 - Ref는 Provider 함수의 첫 번째 인자로 자동 제공되므로 별도 생성이 필요 없습니다

  • ref.onDispose를 활용해 리소스 정리를 확실히 해두면 메모리 누수를 방지할 수 있습니다

2. ref.watch() - 반응형 구독

김개발 씨가 장바구니 기능을 구현하던 중이었습니다. 상품을 추가하면 총 금액이 자동으로 업데이트되어야 하는데, 어떻게 해야 할지 막막했습니다.

"상태가 바뀔 때마다 자동으로 반영되게 하려면 어떻게 해야 하지?"

ref.watch는 다른 Provider의 값을 구독하고, 그 값이 변경될 때마다 현재 Provider를 자동으로 다시 빌드합니다. 마치 유튜브 채널을 구독하면 새 영상이 올라올 때마다 알림을 받는 것과 같습니다.

한 번 watch로 연결해두면 상태 변화가 자동으로 전파됩니다.

다음 코드를 살펴봅시다.

// 장바구니 상품 목록 Provider
final cartItemsProvider = StateProvider<List<CartItem>>((ref) => []);

// 총 금액을 자동으로 계산하는 Provider
final totalPriceProvider = Provider<int>((ref) {
  // cartItemsProvider를 구독 - 변경 시 자동 재계산
  final items = ref.watch(cartItemsProvider);

  // 모든 상품 가격의 합계 계산
  return items.fold(0, (sum, item) => sum + item.price * item.quantity);
});

// 위젯에서 사용
class CartSummary extends ConsumerWidget {
  Widget build(BuildContext context, WidgetRef ref) {
    // totalPrice가 바뀌면 위젯이 자동으로 리빌드
    final totalPrice = ref.watch(totalPriceProvider);
    return Text('총 금액: ${totalPrice}원');
  }
}

김개발 씨는 쇼핑몰 앱의 장바구니 기능을 맡게 되었습니다. 사용자가 상품을 추가하거나 수량을 변경하면 총 금액이 실시간으로 업데이트되어야 했습니다.

처음에는 setState를 떠올렸습니다. 하지만 장바구니 상태는 여러 화면에서 공유되어야 했고, 각 화면마다 수동으로 업데이트하는 건 너무 번거로웠습니다.

박시니어 씨가 다가와 화면을 보더니 말했습니다. "이럴 때 ref.watch를 쓰면 돼.

유튜브 구독 버튼 알지? 한 번 누르면 그 채널의 새 영상이 자동으로 알림이 오잖아.

watch도 똑같아." 이 비유가 김개발 씨의 이해를 도왔습니다. ref.watch로 어떤 Provider를 구독하면, 그 Provider의 값이 변경될 때마다 현재 코드가 자동으로 다시 실행됩니다.

위 코드에서 totalPriceProvidercartItemsProvider를 watch하고 있습니다. 장바구니에 상품이 추가되거나 제거되면, totalPriceProvider가 자동으로 재계산됩니다.

개발자가 직접 "장바구니가 바뀌었으니 총 금액을 다시 계산해"라고 명령할 필요가 없는 것입니다. 더 나아가 CartSummary 위젯에서도 ref.watch를 사용합니다.

totalPriceProvider를 watch하고 있으므로, 총 금액이 바뀌면 위젯이 자동으로 리빌드되어 새로운 금액을 화면에 표시합니다. 이것이 바로 반응형 프로그래밍의 핵심입니다.

데이터의 흐름을 선언적으로 정의해두면, 변경 사항이 자동으로 전파됩니다. 마치 엑셀에서 수식을 정의해두면 참조 셀이 바뀔 때 결과가 자동으로 업데이트되는 것과 같습니다.

주의할 점도 있습니다. watch는 build 메서드 내부에서만 사용해야 합니다.

버튼 클릭 핸들러 같은 곳에서 watch를 쓰면 예상치 못한 동작이 발생할 수 있습니다. 이런 경우에는 read를 사용해야 하는데, 이건 다음 장에서 자세히 다루겠습니다.

김개발 씨는 코드를 수정했습니다. 장바구니에 상품을 추가하자 총 금액이 마법처럼 자동으로 업데이트되었습니다.

"와, 이렇게 간단하게 되는 거였어?" 박시니어 씨가 미소 지으며 말했습니다. "watch의 힘이야.

상태 간의 의존성을 선언만 해두면 Riverpod이 나머지를 알아서 처리해주거든."

실전 팁

💡 - ref.watch는 build 메서드나 Provider 본문에서만 사용하세요

  • 여러 Provider를 watch할 수 있으며, 어느 하나라도 변경되면 리빌드됩니다

3. ref.read() - 일회성 읽기

김개발 씨가 "구매하기" 버튼을 구현하던 중이었습니다. 버튼을 누르면 현재 장바구니 상태를 서버로 전송해야 했는데, watch를 쓰자니 뭔가 이상했습니다.

"버튼 누를 때 한 번만 값을 읽으면 되는데, 구독까지 해야 하나?"

ref.read는 Provider의 현재 값을 딱 한 번만 읽어옵니다. 구독이 아니라 일회성 조회입니다.

마치 신문 구독 대신 가판대에서 오늘 신문만 한 부 사는 것과 같습니다. 이벤트 핸들러나 Provider 초기화처럼 특정 시점의 값만 필요할 때 사용합니다.

다음 코드를 살펴봅시다.

class CheckoutButton extends ConsumerWidget {
  Widget build(BuildContext context, WidgetRef ref) {
    return ElevatedButton(
      onPressed: () {
        // 버튼 클릭 시점의 값만 필요 - read 사용
        final cartItems = ref.read(cartItemsProvider);
        final totalPrice = ref.read(totalPriceProvider);

        // 서버로 주문 전송
        ref.read(orderServiceProvider).placeOrder(
          items: cartItems,
          total: totalPrice,
        );

        // 장바구니 초기화
        ref.read(cartItemsProvider.notifier).state = [];
      },
      child: Text('구매하기'),
    );
  }
}

김개발 씨는 장바구니 화면의 "구매하기" 버튼을 구현하고 있었습니다. 버튼을 누르면 현재 장바구니에 담긴 상품들을 서버로 전송해야 했습니다.

처음에는 습관적으로 ref.watch를 사용하려고 했습니다. 하지만 뭔가 이상했습니다.

버튼의 onPressed 콜백 안에서 watch를 쓰면 린트 경고가 떴습니다. "선배, 여기서는 watch를 쓰면 안 되나요?" 김개발 씨가 물었습니다.

박시니어 씨가 설명했습니다. "watch는 '구독'이야.

값이 바뀔 때마다 다시 실행되어야 하는 곳에서 쓰는 거지. 근데 버튼 클릭은 딱 한 번 실행되는 거잖아.

이럴 땐 read를 써야 해." 비유를 들어보겠습니다. watch가 신문 구독이라면, read는 가판대에서 오늘 신문을 한 부 사는 것입니다.

매일 배달받을 필요 없이, 필요한 그 순간에만 한 번 사면 되는 것이죠. ref.read는 Provider의 현재 값을 일회성으로 읽어옵니다.

구독을 설정하지 않으므로, 나중에 그 Provider의 값이 바뀌어도 아무 일도 일어나지 않습니다. 위 코드를 보면, onPressed 콜백 안에서 ref.read를 사용하고 있습니다.

버튼이 눌린 그 시점의 장바구니 상태와 총 금액을 가져와 주문을 처리합니다. 이후 장바구니가 어떻게 변하든 이 콜백에는 영향이 없습니다.

또 하나 주목할 점은 **ref.read(cartItemsProvider.notifier)**입니다. .notifier를 붙이면 Provider의 상태 자체가 아닌, 상태를 변경할 수 있는 notifier 객체에 접근합니다.

이를 통해 장바구니를 빈 배열로 초기화하고 있습니다. 그렇다면 언제 read를 쓰고 언제 watch를 써야 할까요?

간단한 기준이 있습니다. "이 값이 나중에 바뀌면 여기도 업데이트되어야 하나?"라고 자문해보세요.

답이 "예"라면 watch, "아니오"라면 read입니다. 버튼 클릭, 초기화 로직, 일회성 계산 등에서는 read가 적합합니다.

반면 UI에 표시되는 값처럼 변경을 반영해야 하는 곳에서는 watch를 사용합니다. 김개발 씨는 이제 두 메서드의 차이를 명확히 이해했습니다.

watch는 "구독하고 추적", read는 "지금 한 번만 읽기". 이 구분만 잘해도 Riverpod 코드가 훨씬 깔끔해집니다.

실전 팁

💡 - onPressed, onTap 같은 이벤트 핸들러에서는 항상 read를 사용하세요

  • .notifier를 붙이면 값이 아닌 상태 변경 객체에 접근할 수 있습니다

4. ref.listen() - 사이드 이펙트

김개발 씨에게 새로운 요구사항이 주어졌습니다. 에러가 발생하면 스낵바로 사용자에게 알려야 했습니다.

"상태가 바뀔 때 뭔가를 '실행'해야 하는데, watch로는 UI를 다시 그리는 것밖에 못 하잖아. 어떻게 하지?"

ref.listen은 Provider의 값 변화를 감지하고, 변화가 있을 때 특정 콜백을 실행합니다. watch와 달리 리빌드를 트리거하지 않고, 순수하게 사이드 이펙트만 수행합니다.

스낵바 표시, 네비게이션, 로깅 같은 "값이 바뀌면 이것을 실행해"라는 로직에 완벽하게 맞습니다.

다음 코드를 살펴봅시다.

class OrderPage extends ConsumerWidget {
  Widget build(BuildContext context, WidgetRef ref) {
    // 에러 상태가 바뀌면 스낵바 표시
    ref.listen<AsyncValue<Order>>(orderProvider, (previous, next) {
      // 에러가 발생했을 때만 실행
      if (next.hasError) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('주문 처리 중 오류가 발생했습니다')),
        );
      }

      // 주문 성공 시 결과 페이지로 이동
      if (previous?.isLoading == true && next.hasValue) {
        Navigator.pushNamed(context, '/order-complete');
      }
    });

    // UI 렌더링은 별도로
    return OrderForm();
  }
}

김개발 씨는 주문 기능을 완성해가고 있었습니다. 이번에는 에러 처리가 과제였습니다.

주문 처리 중 에러가 발생하면 스낵바로 사용자에게 알려야 했습니다. 처음에는 watch를 사용해 에러 상태를 감지하고 if문으로 스낵바를 표시하려 했습니다.

하지만 이상한 일이 벌어졌습니다. 빌드 과정에서 스낵바를 표시하니 Flutter가 경고를 내뿜었습니다.

박시니어 씨가 문제를 발견했습니다. "build 메서드 안에서 직접 사이드 이펙트를 실행하면 안 돼.

그건 listen의 영역이야." ref.listen은 watch와 비슷하게 상태 변화를 감지하지만, 동작 방식이 다릅니다. watch는 "값이 바뀌면 이 코드를 다시 빌드해"라고 하는 반면, listen은 "값이 바뀌면 이 함수를 실행해"라고 합니다.

비유하자면, watch는 감시 카메라와 같습니다. 뭔가 감지되면 화면 전체를 새로고침합니다.

반면 listen은 알람 시스템과 같습니다. 뭔가 감지되면 특정 행동(경보 울리기)만 수행하고, 화면은 그대로입니다.

위 코드를 보면, ref.listen은 세 개의 요소로 구성됩니다. 감시할 Provider, 이전 값(previous), 그리고 새 값(next)입니다.

콜백 함수 안에서 두 값을 비교해 원하는 로직을 실행할 수 있습니다. 에러가 발생했는지 확인하려면 next.hasError를 체크합니다.

로딩이 완료되었는지는 previous?.isLoadingnext.hasValue를 비교해 알 수 있습니다. listen의 콜백은 빌드 과정과 분리되어 있어서, 안전하게 스낵바를 표시하거나 페이지 네비게이션을 수행할 수 있습니다.

이것이 바로 "사이드 이펙트"입니다. UI 렌더링과는 별개로 실행되어야 하는 부수적인 효과들이죠.

김개발 씨가 물었습니다. "그럼 listen도 build 안에서 써야 하나요?" 박시니어 씨가 답했습니다.

"맞아. 하지만 initState처럼 한 번만 실행되는 게 아니라, build가 실행될 때마다 리스너가 갱신돼.

Riverpod이 알아서 이전 리스너를 정리하고 새로 등록하거든." 주의할 점이 있습니다. listen 콜백 안에서 ref.read는 사용할 수 있지만, ref.watch는 사용하면 안 됩니다.

콜백은 빌드 컨텍스트가 아니기 때문입니다.

실전 팁

💡 - 스낵바, 다이얼로그, 네비게이션 같은 사이드 이펙트에는 listen을 사용하세요

  • listen의 콜백은 비동기(async)로 만들 수 있어 API 호출도 가능합니다

5. 언제 watch를 쓰고 언제 read를 쓸까?

김개발 씨의 코드 리뷰 시간이었습니다. 선배가 코드를 보더니 물었습니다.

"여기 왜 watch를 썼어? read가 맞지 않아?" 김개발 씨는 당황했습니다.

둘의 차이는 알겠는데, 실제로 어떤 상황에 뭘 써야 하는지 헷갈렸던 것입니다.

watchread의 선택 기준은 명확합니다. "이 값이 변경되면 여기도 업데이트되어야 하는가?"입니다.

UI에 표시되는 값, 다른 상태를 파생하는 계산에는 watch를 사용합니다. 버튼 클릭, 초기화, 일회성 작업에는 read를 사용합니다.

잘못 사용하면 불필요한 리빌드가 발생하거나, 반대로 UI가 업데이트되지 않는 버그가 생깁니다.

다음 코드를 살펴봅시다.

class ProductPage extends ConsumerWidget {
  Widget build(BuildContext context, WidgetRef ref) {
    // UI에 표시할 값 - watch 사용 (변경 시 리빌드 필요)
    final product = ref.watch(productProvider);
    final isFavorite = ref.watch(favoriteProvider);

    return Column(
      children: [
        Text(product.name),  // 상품명이 바뀌면 업데이트
        IconButton(
          icon: Icon(isFavorite ? Icons.favorite : Icons.favorite_border),
          onPressed: () {
            // 이벤트 핸들러 - read 사용 (한 번만 실행)
            final currentFavorite = ref.read(favoriteProvider);
            ref.read(favoriteProvider.notifier).state = !currentFavorite;

            // 서버에 저장
            ref.read(apiProvider).saveFavorite(!currentFavorite);
          },
        ),
      ],
    );
  }
}

코드 리뷰를 받은 김개발 씨는 watch와 read의 사용 기준을 제대로 정리하고 싶었습니다. 박시니어 씨에게 명확한 가이드라인을 요청했습니다.

박시니어 씨는 화이트보드에 표를 그렸습니다. "간단해.

이 질문 하나만 기억하면 돼. '이 값이 나중에 바뀌면 여기도 업데이트되어야 해?'" 답이 "예"라면 watch입니다.

화면에 표시되는 텍스트, 조건에 따라 바뀌는 아이콘, 다른 상태를 기반으로 계산되는 값 등이 여기에 해당합니다. 답이 "아니오"라면 read입니다.

버튼을 눌렀을 때 실행되는 로직, 초기화 코드, 일회성 계산 등이 이에 속합니다. 위 코드를 예로 들어보겠습니다.

productisFavorite는 UI에 직접 표시됩니다. 상품 정보가 바뀌면 화면도 업데이트되어야 하고, 즐겨찾기 상태가 바뀌면 아이콘도 바뀌어야 합니다.

따라서 watch를 사용합니다. 반면 onPressed 콜백 안에서는 read를 사용합니다.

버튼이 눌린 그 순간의 즐겨찾기 상태만 알면 됩니다. 나중에 상태가 바뀌어도 이미 실행이 끝난 콜백에는 영향이 없습니다.

실수하기 쉬운 부분을 짚어보겠습니다. 만약 onPressed 안에서 watch를 사용하면 어떻게 될까요?

Riverpod은 경고를 표시합니다. 이벤트 핸들러는 빌드 컨텍스트가 아니기 때문에 구독을 설정할 수 없습니다.

반대로 build 메서드에서 UI에 표시할 값을 read로 가져오면 어떨까요? 화면은 처음 한 번만 그려지고, 상태가 바뀌어도 업데이트되지 않습니다.

사용자는 오래된 정보를 보게 됩니다. 박시니어 씨가 추가 팁을 알려주었습니다.

"위젯 클래스 안에서 함수를 분리할 때 주의해야 해. 분리된 함수가 build 안에서 호출되더라도, 그 함수 안에서 watch를 쓰면 안 돼.

watch는 항상 build 메서드의 직접적인 본문에서만 사용해야 해." 이 원칙을 지키면 대부분의 상황에서 올바른 선택을 할 수 있습니다. 불필요한 리빌드를 방지하고, 동시에 UI가 항상 최신 상태를 반영하도록 보장할 수 있습니다.

실전 팁

💡 - 간단한 규칙: build 본문에서는 watch, 콜백에서는 read

  • 성능 최적화를 위해 select를 사용하면 특정 필드만 구독할 수 있습니다

6. 흔한 실수와 해결법

김개발 씨가 작성한 코드가 이상하게 동작했습니다. 분명히 상태를 바꿨는데 화면이 안 바뀌거나, 반대로 너무 자주 리빌드가 일어났습니다.

박시니어 씨는 이런 실수들이 Riverpod 입문자에게 흔히 나타난다고 했습니다.

Riverpod을 처음 사용할 때 자주 발생하는 실수들이 있습니다. 이벤트 핸들러에서 watch 사용하기, build에서 read로 UI 값 가져오기, Provider 안에서 무한 루프 만들기 등이 대표적입니다.

이러한 실수의 원인과 해결책을 알면 디버깅 시간을 크게 줄일 수 있습니다.

다음 코드를 살펴봅시다.

// 실수 1: 이벤트 핸들러에서 watch 사용
onPressed: () {
  final value = ref.watch(provider);  // 잘못됨!
  final value = ref.read(provider);   // 올바름
}

// 실수 2: build에서 read로 UI 값 가져오기
Widget build(context, ref) {
  final count = ref.read(countProvider);  // 업데이트 안 됨!
  final count = ref.watch(countProvider); // 올바름
  return Text('$count');
}

// 실수 3: 조건부 watch (hooks처럼 사용)
if (condition) {
  ref.watch(providerA);  // 조건에 따라 watch가 달라지면 위험!
}
// 해결: 항상 watch하고 조건은 사용 시점에 적용
final valueA = ref.watch(providerA);
if (condition) { /* valueA 사용 */ }

김개발 씨는 몇 번의 삽질 끝에 Riverpod의 함정들을 하나씩 경험했습니다. 박시니어 씨는 이런 실수들을 미리 정리해두면 좋겠다고 했습니다.

첫 번째 흔한 실수는 이벤트 핸들러에서 watch를 사용하는 것입니다. onPressed, onTap, onChanged 같은 콜백 안에서 watch를 쓰면 런타임 에러가 발생하거나 예상치 못한 동작이 일어납니다.

이유는 간단합니다. 이벤트 핸들러는 빌드 과정의 일부가 아니기 때문입니다.

해결책은 항상 read를 사용하는 것입니다. 두 번째 실수는 build 메서드에서 read로 UI 값을 가져오는 것입니다.

이렇게 하면 화면은 한 번만 그려지고, 상태가 바뀌어도 업데이트되지 않습니다. 김개발 씨도 이 실수를 했습니다.

카운터 앱에서 버튼을 아무리 눌러도 숫자가 안 바뀌어서 한참을 헤맸습니다. 해결책은 UI에 표시할 값은 반드시 watch로 가져오는 것입니다.

세 번째 실수는 조건부 watch입니다. if문 안에서 watch를 사용하면, 조건에 따라 구독 여부가 달라집니다.

이는 React의 훅 규칙과 비슷한 문제를 일으킵니다. Riverpod은 매 빌드마다 동일한 순서로 동일한 Provider들이 watch되기를 기대합니다.

해결책은 watch는 항상 무조건적으로 하고, 조건은 값을 사용할 때 적용하는 것입니다. 네 번째 실수는 Provider 안에서 자기 자신을 watch하거나 순환 참조를 만드는 것입니다.

A가 B를 watch하고 B가 A를 watch하면 무한 루프에 빠집니다. Riverpod이 이를 감지해 에러를 던지지만, 복잡한 의존성 그래프에서는 발견하기 어려울 수 있습니다.

Provider 간의 의존성은 단방향으로 유지하는 것이 좋습니다. 다섯 번째는 불필요하게 넓은 범위를 watch하는 것입니다.

큰 객체 전체를 watch하면 그 객체의 어떤 필드가 바뀌든 리빌드가 발생합니다. 만약 특정 필드만 필요하다면 select를 사용해 해당 필드만 구독할 수 있습니다.

예를 들어 ref.watch(userProvider.select((user) => user.name))처럼 쓰면 name이 바뀔 때만 리빌드됩니다. 박시니어 씨가 정리했습니다.

"이 다섯 가지만 기억해. 대부분의 Riverpod 버그는 여기서 나와." 김개발 씨는 이 내용을 노트에 적어두었습니다.

실전 팁

💡 - IDE의 린트 규칙을 활성화하면 많은 실수를 컴파일 타임에 잡을 수 있습니다

  • 디버깅이 어려우면 ProviderObserver를 구현해 상태 변화를 로깅해보세요

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

#Flutter#Riverpod#ref.watch#ref.read#StateManagement#Flutter,State Management

댓글 (0)

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

함께 보면 좋은 카드 뉴스