본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 30. · 13 Views
Notifier와 NotifierProvider 완벽 가이드
Flutter Riverpod 2.0의 핵심인 Notifier와 NotifierProvider를 초급자도 쉽게 이해할 수 있도록 설명합니다. 상태 관리의 새로운 표준을 마스터해보세요.
목차
- Notifier란?
- NotifierProvider 선언
- state 업데이트 패턴
- 메서드로 상태 변경
- 불변 상태와 copyWith
- Notifier vs StateNotifier(레거시)
1. Notifier란?
김개발 씨는 Flutter로 첫 번째 앱을 만들고 있었습니다. 화면에 숫자를 표시하고 버튼을 누르면 숫자가 증가하는 간단한 카운터 앱이었습니다.
그런데 상태 관리를 어떻게 해야 할지 막막했습니다. "StatefulWidget을 쓰면 되지 않나요?" 옆자리 박시니어 씨가 고개를 저었습니다.
"더 좋은 방법이 있어요. Notifier를 써보세요."
Notifier는 Riverpod 2.0에서 도입된 상태 관리 클래스입니다. 마치 식당의 주방장이 요리 상태를 관리하듯, Notifier는 앱의 상태를 체계적으로 관리합니다.
상태를 변경하는 로직과 상태 자체를 한 곳에서 캡슐화할 수 있어 코드가 훨씬 깔끔해집니다.
다음 코드를 살펴봅시다.
// Notifier 클래스 정의: 상태 타입을 제네릭으로 지정합니다
class CounterNotifier extends Notifier<int> {
// build 메서드: 초기 상태를 반환합니다
@override
int build() {
// 초기값 0으로 시작
return 0;
}
// 상태를 변경하는 메서드
void increment() {
// state에 직접 새 값을 할당합니다
state = state + 1;
}
void decrement() {
state = state - 1;
}
}
김개발 씨는 입사 3개월 차 주니어 개발자입니다. 오늘도 열심히 Flutter 코드를 작성하던 중, 상태 관리 때문에 머리가 복잡해졌습니다.
setState를 여기저기 흩뿌려 놓으니 코드가 스파게티처럼 엉켜버렸기 때문입니다. 선배 개발자 박시니어 씨가 다가와 코드를 살펴봅니다.
"아, 상태 관리가 문제네요. Notifier를 사용해보는 건 어때요?" 그렇다면 Notifier란 정확히 무엇일까요?
쉽게 비유하자면, Notifier는 마치 은행의 금고 관리인과 같습니다. 금고 안의 돈이 바로 **상태(state)**이고, 관리인만이 금고를 열고 돈을 넣거나 뺄 수 있습니다.
아무나 금고에 손을 댈 수 없듯이, Notifier 외부에서는 상태를 직접 변경할 수 없습니다. 이처럼 Notifier도 상태의 안전한 관리를 담당합니다.
Notifier가 없던 시절에는 어땠을까요? 개발자들은 StatefulWidget의 setState를 직접 호출해야 했습니다.
화면이 복잡해지면 상태 변경 코드가 여기저기 흩어져 버그를 찾기 어려웠습니다. 더 큰 문제는 상태 로직을 재사용하기 힘들다는 것이었습니다.
프로젝트가 커질수록 이런 문제는 눈덩이처럼 불어났습니다. 바로 이런 문제를 해결하기 위해 Notifier가 등장했습니다.
Notifier를 사용하면 상태와 로직을 한 곳에서 관리할 수 있습니다. 또한 테스트하기도 훨씬 쉬워집니다.
무엇보다 코드의 예측 가능성이 높아진다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 **Notifier<int>**를 상속받는 부분을 보면 이 Notifier가 int 타입의 상태를 관리한다는 것을 알 수 있습니다. 다음으로 build 메서드에서는 초기 상태값 0을 반환합니다.
이 메서드는 Notifier가 처음 생성될 때 자동으로 호출됩니다. 마지막으로 increment와 decrement 메서드에서 state에 새 값을 할당하면 UI가 자동으로 업데이트됩니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 쇼핑몰 앱의 장바구니를 개발한다고 가정해봅시다.
장바구니의 상품 목록이 상태가 되고, 상품 추가, 삭제, 수량 변경이 메서드가 됩니다. Notifier를 활용하면 장바구니 로직을 깔끔하게 분리할 수 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 build 메서드 안에서 비동기 작업을 하는 것입니다.
비동기 초기화가 필요하다면 AsyncNotifier를 사용해야 합니다. 일반 Notifier의 build는 동기적으로 동작합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.
"아, 상태와 로직을 한 곳에서 관리하는 거군요!" Notifier를 제대로 이해하면 더 깔끔하고 유지보수하기 쉬운 상태 관리 코드를 작성할 수 있습니다.
실전 팁
💡 - build 메서드는 반드시 동기적으로 초기값을 반환해야 합니다
- 상태 타입은 제네릭으로 명시하여 타입 안전성을 확보하세요
2. NotifierProvider 선언
김개발 씨가 Notifier 클래스를 만들었습니다. 그런데 막상 이걸 어떻게 사용해야 할지 모르겠습니다.
"Notifier를 만들었는데, 이걸 어디서 어떻게 불러오죠?" 박시니어 씨가 웃으며 대답했습니다. "Notifier는 혼자서는 일할 수 없어요.
NotifierProvider라는 파트너가 필요합니다."
NotifierProvider는 Notifier를 Riverpod 시스템에 등록하는 역할을 합니다. 마치 회사에서 직원을 채용하려면 인사팀에 등록해야 하듯, Notifier도 NotifierProvider를 통해 등록되어야 앱 전체에서 사용할 수 있습니다.
Provider가 있어야 위젯에서 상태를 읽고 메서드를 호출할 수 있습니다.
다음 코드를 살펴봅시다.
// Notifier 클래스 정의
class TodoListNotifier extends Notifier<List<String>> {
@override
List<String> build() {
return []; // 빈 리스트로 시작
}
void addTodo(String todo) {
state = [...state, todo];
}
}
// NotifierProvider 선언: Notifier와 상태 타입을 명시합니다
final todoListProvider = NotifierProvider<TodoListNotifier, List<String>>(() {
return TodoListNotifier();
});
김개발 씨는 Notifier 클래스를 완성하고 뿌듯한 마음으로 코드를 저장했습니다. 그런데 문제가 생겼습니다.
위젯에서 이 Notifier를 어떻게 가져와서 사용해야 할까요? 박시니어 씨가 다가와 설명을 시작했습니다.
"Notifier만으로는 부족해요. NotifierProvider가 필요합니다." 그렇다면 NotifierProvider란 무엇일까요?
쉽게 비유하자면, NotifierProvider는 마치 전화번호부와 같습니다. Notifier가 전화기라면, 전화번호부에 등록되어 있어야 다른 사람들이 전화를 걸 수 있습니다.
NotifierProvider에 등록된 Notifier만이 앱 전체에서 접근 가능합니다. NotifierProvider 없이 Notifier만 있으면 어떻게 될까요?
위젯에서 Notifier에 접근할 방법이 없습니다. 직접 인스턴스를 만들 수는 있지만, 그러면 상태가 위젯마다 따로 관리됩니다.
앱 전체에서 하나의 상태를 공유하려면 반드시 Provider가 필요합니다. Provider 선언 방식을 자세히 살펴보겠습니다.
**NotifierProvider<TodoListNotifier, List<String>>**에서 첫 번째 제네릭은 Notifier 클래스 타입, 두 번째는 상태 타입입니다. 이렇게 두 가지 타입을 명시하면 컴파일 타임에 타입 검사가 이루어져 실수를 방지할 수 있습니다.
콜백 함수 **() => TodoListNotifier()**는 Notifier 인스턴스를 생성하는 역할을 합니다. 이 함수는 Provider가 처음 읽힐 때 호출됩니다.
즉, 필요할 때까지 Notifier 생성이 지연됩니다. 이를 **지연 초기화(lazy initialization)**라고 합니다.
실제 프로젝트에서는 Provider를 어디에 선언할까요? 보통 lib/providers 폴더를 만들어 관련 Provider들을 모아둡니다.
또는 해당 기능의 폴더에 함께 두기도 합니다. 중요한 것은 final 키워드로 전역 변수처럼 선언한다는 점입니다.
이렇게 해도 안전한 이유는 실제 상태는 Riverpod이 관리하기 때문입니다. 주의할 점이 있습니다.
Provider 이름은 관례적으로 ~Provider로 끝납니다. todoList가 아니라 todoListProvider처럼 말이죠.
이 규칙을 지키면 코드를 읽을 때 무엇이 Provider인지 한눈에 알 수 있습니다. 김개발 씨가 고개를 끄덕였습니다.
"아, Provider가 있어야 위젯에서 사용할 수 있군요!"
실전 팁
💡 - Provider 이름은 ~Provider로 끝나도록 지어 가독성을 높이세요
- Provider는 보통 파일 최상위 레벨에 final로 선언합니다
3. state 업데이트 패턴
김개발 씨가 Notifier와 Provider를 연결했습니다. 이제 상태를 변경해볼 차례입니다.
"그냥 state = newValue 하면 되나요?" 박시니어 씨가 고개를 끄덕이며 덧붙였습니다. "맞아요, 하지만 몇 가지 알아둘 패턴이 있어요."
Notifier에서 상태를 업데이트하는 방법은 state 속성에 새 값을 할당하는 것입니다. 마치 칠판의 내용을 지우고 새로 쓰는 것처럼, 기존 상태를 새 상태로 완전히 교체합니다.
이때 Riverpod이 자동으로 변경을 감지하고 UI를 업데이트합니다.
다음 코드를 살펴봅시다.
class ScoreNotifier extends Notifier<int> {
@override
int build() => 0;
// 단순 값 업데이트
void setScore(int newScore) {
state = newScore; // 새 값으로 교체
}
// 현재 상태 기반 업데이트
void addPoints(int points) {
state = state + points; // 현재 값에 더하기
}
// 조건부 업데이트
void resetIfNegative() {
if (state < 0) {
state = 0; // 조건 만족시에만 업데이트
}
}
}
김개발 씨가 드디어 상태를 변경하는 코드를 작성하려 합니다. 그런데 StatefulWidget에서 쓰던 setState와는 사용법이 다른 것 같습니다.
박시니어 씨가 설명을 시작했습니다. "Notifier에서는 state라는 특별한 속성을 사용해요." state는 Notifier 클래스 내부에서만 접근할 수 있는 속성입니다.
외부에서는 직접 수정할 수 없고, 오직 Notifier의 메서드를 통해서만 변경할 수 있습니다. 이것이 바로 캡슐화의 핵심입니다.
상태 업데이트는 크게 세 가지 패턴으로 나눌 수 있습니다. 첫 번째는 단순 값 교체입니다.
setScore 메서드처럼 새로운 값을 그대로 할당합니다. 이전 상태와 관계없이 완전히 새로운 값으로 바꿀 때 사용합니다.
두 번째는 현재 상태 기반 업데이트입니다. addPoints 메서드처럼 현재 state 값을 읽어서 계산한 후 새 값을 할당합니다.
카운터 증가, 점수 합산 등에 활용됩니다. 세 번째는 조건부 업데이트입니다.
resetIfNegative처럼 특정 조건을 만족할 때만 상태를 변경합니다. 불필요한 리빌드를 방지할 수 있습니다.
중요한 점이 있습니다. state에 같은 값을 다시 할당하면 어떻게 될까요?
Riverpod은 값이 실제로 변경되었는지 확인합니다. 같은 값이면 UI를 다시 빌드하지 않습니다.
이것은 성능 최적화에 큰 도움이 됩니다. 하지만 주의해야 할 점도 있습니다.
리스트나 객체의 경우, 내부 값만 변경하면 Riverpod이 변경을 감지하지 못합니다. 예를 들어 **state.add(item)**은 동작하지 않습니다.
반드시 **state = [...state, item]**처럼 새 리스트를 할당해야 합니다. 김개발 씨가 이해했다는 표정을 지었습니다.
"아, 그래서 불변성이 중요한 거군요!"
실전 팁
💡 - 같은 값을 할당하면 리빌드가 발생하지 않습니다
- 리스트나 객체는 반드시 새 인스턴스를 생성하여 할당하세요
4. 메서드로 상태 변경
김개발 씨가 코드 리뷰를 받는 중입니다. "여기 상태 변경 로직이 위젯에 있네요.
이건 Notifier 안으로 옮기는 게 좋겠어요." 박시니어 씨의 조언에 김개발 씨가 궁금해졌습니다. "왜 위젯에서 직접 변경하면 안 되나요?"
Notifier에서 상태 변경은 메서드를 통해 이루어져야 합니다. 마치 은행에서 돈을 찾으려면 창구 직원에게 요청해야 하듯, 상태 변경도 정해진 메서드를 통해서만 가능합니다.
이렇게 하면 비즈니스 로직을 한 곳에서 관리할 수 있고, 테스트하기도 쉬워집니다.
다음 코드를 살펴봅시다.
class CartNotifier extends Notifier<List<CartItem>> {
@override
List<CartItem> build() => [];
// 상품 추가 메서드
void addItem(CartItem item) {
// 이미 있는 상품인지 확인하는 로직
final existingIndex = state.indexWhere((e) => e.id == item.id);
if (existingIndex >= 0) {
// 수량만 증가
state = [
for (var i = 0; i < state.length; i++)
if (i == existingIndex) state[i].copyWith(quantity: state[i].quantity + 1)
else state[i]
];
} else {
state = [...state, item];
}
}
// 전체 비우기
void clearCart() => state = [];
}
김개발 씨가 장바구니 기능을 개발하고 있었습니다. 처음에는 위젯에서 직접 상태를 조작하는 코드를 작성했습니다.
그런데 코드 리뷰에서 문제가 지적되었습니다. 박시니어 씨가 설명합니다.
"상태 변경 로직이 위젯에 있으면 나중에 문제가 생겨요." 왜 메서드로 캡슐화해야 할까요? 첫째, 비즈니스 로직의 중앙화입니다.
장바구니에 상품을 추가할 때 중복 체크를 한다고 가정해봅시다. 이 로직이 여러 위젯에 흩어져 있으면 하나를 수정할 때 다른 곳도 찾아서 수정해야 합니다.
Notifier에 메서드로 정의하면 한 곳만 수정하면 됩니다. 둘째, 테스트 용이성입니다.
addItem 메서드가 제대로 동작하는지 테스트하려면 Notifier만 테스트하면 됩니다. UI와 분리되어 있어 단위 테스트가 간단해집니다.
셋째, 재사용성입니다. 같은 addItem 로직을 여러 화면에서 사용할 수 있습니다.
상품 목록 페이지에서도, 상품 상세 페이지에서도 같은 메서드를 호출하면 됩니다. 위 코드를 살펴보겠습니다.
addItem 메서드는 단순히 상품을 추가하는 것이 아닙니다. 먼저 이미 존재하는 상품인지 확인합니다.
존재한다면 수량만 증가시키고, 새 상품이라면 리스트에 추가합니다. 이런 복잡한 로직이 위젯에 있으면 코드가 지저분해집니다.
메서드 이름을 지을 때는 의도를 명확히 드러내야 합니다. addItem은 상품을 추가한다는 의미, clearCart는 장바구니를 비운다는 의미가 명확합니다.
나중에 코드를 읽을 때 메서드 이름만 보고도 무슨 일을 하는지 알 수 있어야 합니다. 김개발 씨가 고개를 끄덕였습니다.
"메서드로 분리하니까 훨씬 깔끔하네요!"
실전 팁
💡 - 메서드 이름은 동작을 명확히 나타내도록 지으세요
- 하나의 메서드는 하나의 책임만 갖도록 설계하세요
5. 불변 상태와 copyWith
김개발 씨가 사용자 프로필 수정 기능을 구현하고 있습니다. 이름만 바꾸고 싶은데, 전체 객체를 다시 만들어야 할까요?
"매번 새 객체를 만드는 게 비효율적인 것 같은데요." 박시니어 씨가 미소를 지으며 답했습니다. "그래서 copyWith 패턴이 있어요."
Flutter에서 상태는 **불변(immutable)**으로 관리하는 것이 원칙입니다. 객체의 일부만 변경하고 싶을 때 copyWith 메서드를 사용합니다.
마치 서류를 복사한 후 필요한 부분만 수정하는 것처럼, 기존 객체를 기반으로 일부 값만 바꾼 새 객체를 생성합니다.
다음 코드를 살펴봅시다.
// 불변 상태 클래스 정의
class UserProfile {
final String name;
final String email;
final int age;
const UserProfile({required this.name, required this.email, required this.age});
// copyWith 메서드: 일부만 변경한 새 객체 생성
UserProfile copyWith({String? name, String? email, int? age}) {
return UserProfile(
name: name ?? this.name,
email: email ?? this.email,
age: age ?? this.age,
);
}
}
class UserNotifier extends Notifier<UserProfile> {
@override
UserProfile build() => const UserProfile(name: '', email: '', age: 0);
void updateName(String newName) {
state = state.copyWith(name: newName); // 이름만 변경
}
}
김개발 씨가 사용자 프로필을 관리하는 Notifier를 만들었습니다. 사용자가 이름을 변경하면 이름만 업데이트해야 합니다.
그런데 상태 객체의 필드를 직접 수정할 수 있을까요? 박시니어 씨가 고개를 저었습니다.
"Flutter에서는 불변성을 유지해야 해요." 불변성이란 무엇일까요? 한번 생성된 객체는 변경하지 않는다는 원칙입니다.
마치 공증된 문서처럼, 원본은 그대로 두고 수정이 필요하면 새 문서를 만드는 것입니다. 이렇게 하면 상태 변경을 추적하기 쉽고, 버그를 예방할 수 있습니다.
그렇다면 객체의 일부만 바꾸고 싶을 때는 어떻게 할까요? 바로 copyWith 패턴입니다.
이 메서드는 현재 객체를 복사하면서 지정한 필드만 새 값으로 대체합니다. name만 전달하면 name만 바뀌고 나머지는 그대로 유지됩니다.
코드를 자세히 살펴보겠습니다. copyWith 메서드의 매개변수들은 모두 nullable입니다.
null이면 기존 값을 유지하고, 값이 전달되면 그 값을 사용합니다. **??
연산자**가 바로 이 로직을 처리합니다. 실무에서는 어떻게 활용할까요?
API에서 받아온 데이터를 로컬에서 수정할 때 유용합니다. 서버에 다시 보내기 전까지 원본 데이터를 보존하면서 UI에는 수정된 값을 보여줄 수 있습니다.
실수로 원본을 훼손할 걱정이 없습니다. 주의할 점이 있습니다.
copyWith를 직접 작성하면 필드가 추가될 때마다 메서드도 수정해야 합니다. 이런 번거로움을 줄이려면 freezed 패키지를 사용하면 자동으로 생성해줍니다.
김개발 씨가 이해했습니다. "원본은 두고 복사본을 수정하는 거군요!"
실전 팁
💡 - freezed 패키지를 사용하면 copyWith가 자동 생성됩니다
- 클래스의 모든 필드를 final로 선언하여 불변성을 보장하세요
6. Notifier vs StateNotifier(레거시)
김개발 씨가 회사의 기존 프로젝트를 살펴보다가 StateNotifier라는 것을 발견했습니다. 인터넷에서 배운 Notifier와는 다른 것 같습니다.
"이 두 개는 뭐가 다른 건가요?" 박시니어 씨가 설명을 시작했습니다. "StateNotifier는 예전 방식이에요.
이제는 Notifier를 사용하는 게 좋아요."
StateNotifier는 Riverpod 1.x에서 사용하던 상태 관리 클래스입니다. Riverpod 2.0부터는 Notifier로 대체되었습니다.
마치 피처폰에서 스마트폰으로 넘어간 것처럼, Notifier가 더 현대적이고 사용하기 쉽습니다. 기존 프로젝트가 아니라면 Notifier를 사용하는 것이 권장됩니다.
다음 코드를 살펴봅시다.
// [레거시] StateNotifier 방식
class OldCounterNotifier extends StateNotifier<int> {
OldCounterNotifier() : super(0); // 생성자에서 초기값 전달
void increment() => state = state + 1;
}
final oldProvider = StateNotifierProvider<OldCounterNotifier, int>(
(ref) => OldCounterNotifier()
);
// [권장] Notifier 방식
class NewCounterNotifier extends Notifier<int> {
@override
int build() => 0; // build 메서드에서 초기값 반환
void increment() => state = state + 1;
}
final newProvider = NotifierProvider<NewCounterNotifier, int>(
() => NewCounterNotifier()
);
김개발 씨가 회사의 레거시 코드를 유지보수하게 되었습니다. 그런데 상태 관리 코드가 익숙한 것과 달라 보입니다.
StateNotifier라는 클래스를 사용하고 있었습니다. 박시니어 씨가 역사를 설명해줍니다.
"Riverpod도 진화해왔어요." StateNotifier는 Riverpod 1.x 시절의 상태 관리 방식입니다. 원래 별도의 패키지(state_notifier)로 존재했고, Riverpod이 이를 채택해서 사용했습니다.
잘 동작하지만 몇 가지 불편한 점이 있었습니다. 어떤 점이 불편했을까요?
첫째, 초기화 방식이 다릅니다. StateNotifier는 생성자의 super()에서 초기값을 전달합니다.
Notifier는 build() 메서드에서 반환합니다. build 방식이 더 유연해서 ref에 접근하여 다른 Provider를 읽을 수 있습니다.
둘째, Provider 내부에서 ref 접근입니다. StateNotifier에서는 생성자에 ref를 따로 전달해야 했습니다.
Notifier는 기본적으로 this.ref로 접근할 수 있어 훨씬 편리합니다. 셋째, 일관성입니다.
Notifier, AsyncNotifier, StreamNotifier 등이 모두 같은 패턴을 따릅니다. 하나를 배우면 나머지도 쉽게 익힐 수 있습니다.
코드를 비교해보겠습니다. StateNotifier는 **super(0)**으로 초기값을 전달합니다.
Notifier는 build() => 0으로 반환합니다. Provider 선언도 StateNotifierProvider와 NotifierProvider로 다릅니다.
그렇다면 기존 StateNotifier 코드를 마이그레이션해야 할까요? 급하게 바꿀 필요는 없습니다.
StateNotifier는 여전히 동작합니다. 하지만 신규 코드는 Notifier로 작성하는 것이 좋습니다.
시간이 날 때 조금씩 마이그레이션하면 됩니다. 마이그레이션은 어렵지 않습니다.
클래스 상속을 변경하고, 생성자의 super()를 build() 메서드로 옮기면 됩니다. Provider 타입도 NotifierProvider로 바꾸면 완료입니다.
김개발 씨가 안심했습니다. "아, 기존 코드를 당장 바꾸지 않아도 되는군요.
새 코드만 Notifier로 작성하면 되겠네요!"
실전 팁
💡 - 신규 프로젝트는 반드시 Notifier를 사용하세요
- 레거시 코드는 천천히 마이그레이션해도 괜찮습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
LangGraph Fault Tolerance 장애 복구 완벽 가이드
LangGraph 애플리케이션의 장애 복구 메커니즘을 실무 중심으로 배웁니다. Durable Execution부터 Graph Migrations까지 체크포인트 기반 복구 시스템을 스토리텔링으로 쉽게 이해할 수 있습니다.
LangGraph Time Travel 완벽 가이드
LangGraph의 Time Travel 기능으로 특정 시점으로 돌아가고, 상태를 포크하여 분기하고, 대안 경로를 탐색하는 방법을 배웁니다. 실무에서 디버깅과 실험에 활용하는 실전 가이드입니다.
LangGraph Persistence 완벽 가이드
LangGraph의 Persistence 기능을 활용하여 대화 상태를 저장하고 관리하는 방법을 배웁니다. Thread와 Checkpoint를 이해하고, 상태 조회 및 수정 방법을 실무 중심으로 학습합니다.
Riverpod 3.0 쇼핑 앱 종합 프로젝트 완벽 가이드
Flutter와 Riverpod 3.0을 활용한 실무 수준의 쇼핑 앱 개발 과정을 단계별로 학습합니다. 상품 목록, 장바구니, 주문, 인증, 검색 기능까지 모든 핵심 기능을 구현하며 상태 관리의 실전 노하우를 익힙니다.
Riverpod 3.0 Retry 자동 재시도 완벽 가이드
Riverpod 3.0에 새로 추가된 Retry 기능을 활용하여 네트워크 오류나 일시적인 실패 상황에서 자동으로 재시도하는 방법을 배웁니다. 초급 개발자도 쉽게 따라할 수 있도록 실무 예제와 함께 설명합니다.