해당 게시글은 2023-09-15 기준으로
riverpod-v2 공식문서를 읽어보며 이해한 내용입니다.
따라서 provider은 GET 요청에 완벽하게 적합
final providerName = SomeProvider.someModifier<Result>((ref){
//my_logic
return Result();
});
Provider: 상태변경 없을때 사용
NotifierProvider: 상태변경 있을시 사용
FutureProvider: Future이면서 상태변경 없을때 사용
AsyncNotifierProvider: Future이면서 상태변경 있을때 사용
autoDispose : provider가 사용을 중지할 때, 캐시를 자동으로 지운다
family : provider에게 인수를 전달한다.
Provider은 상태를 수정할 수 있는 방법을 노출하지 않는다.
이는 상태를 제한된 방식으로만 수정되고, 목적을 분리하기 위함이다.
그러므로 Provider를 상태를 수정하는 방법을 명시적으로 노출해야 한다.
이를 위해 Notifier를 사용하는 것이다.
final providerName = SomeNotifierProvider.someModifier<MyNotifier, Result>(MyNotifier.new);
class MyNotifier extends SomeNotifier<Result> {
Result build() {
<your logic here>
}
<your methods here>
}
! 주로 API 통신시, AsyncNotifierProvider를 가장 많이 사용할 것이다.
The parameter of "notifier providers" is a function which is expected to instantiate the "notifier".
It generally should be a "constructor tear-off".
이전의 StateNotifer와는 다르게 생성자를 받지 않는다.
이 해당 클래스를 통해 Provider의 상태를 수정하는 방법을 노출시킨다.
해당 메서드를 사용하려면 ref.read(someProvider.notifier).method();
와 같은방법으로 일반적인 provider와 동일하게 사용한다.
! Notifier은 state를 제외한 다른 속성은 없어야 하며, UI는 state가 변경되었음을 알수 없다
NotifierProvider 사용하려면 -> Notifier
AsyncNotifierProvider 사용하려면 -> AsyncNotifier
AsyncNotifierProvider.autoDispose 사용하려면 -> AutoDisposeAsyncNotifier
AsyncNotifierProvider.autoDispose.family 사용하려면 -> AutoDisposeFamilyAsyncNotifier
모든 Notifier는 build메서드를 재정의 해야한다.
This method is equivalent to the place where you would normally put your logic in a non-notifier provider.(notifier가 아닌 일반 Provider에서 초기화하기전에 하는 작업을 build 메서드에서 수행한다)
해당 build 메서드를 직접호출해서는 안된다.
final todoListProvider =
AsyncNotifierProvider.autoDispose<TodoList, List<Todo>>(
TodoList.new,
);
// We use an AsyncNotifier because our logic is asynchronous.
// More specifically, we'll need AutoDisposeAsyncNotifier because
// of the "autoDispose" modifier.
class TodoList extends AutoDisposeAsyncNotifier<List<Todo>> {
Future<List<Todo>> build() async {
// The logic we previously had in our FutureProvider is now in the build method.
return [
Todo(description: 'Learn Flutter', completed: true),
Todo(description: 'Learn Riverpod'),
];
}
}
! 위젯 내에서 Provider를 읽는 방법은 동일하게 ref.watch(todoListProvider)를 사용한다.
class TodoList extends AutoDisposeAsyncNotifier<List<Todo>> {
Future<List<Todo>> build() async => [/* ... */];
Future<void> addTodo(Todo todo) async {
await http.post(
Uri.https('your_api.com', '/todos'),
// We serialize our Todo object and POST it to the server.
headers: {'Content-Type': 'application/json'},
body: jsonEncode(todo.toJson()),
);
}
}
해당 addTodo를 구현하여 POST 메서드를 사용한다.
ref.read(todoListProvider.notifier)
.addTodo(Todo(description: 'This is a new todo'));
Future<void> addTodo(Todo todo) async {
// The POST request will return a List<Todo> matching the new application state
final response = await http.post(
Uri.https('your_api.com', '/todos'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(todo.toJson()),
);
// We decode the API response and convert it to a List<Todo>
List<Todo> newTodos = (jsonDecode(response.body) as List)
.cast<Map<String, Object?>>()
.map(Todo.fromJson)
.toList();
// We update the local cache to match the new state.
// This will notify all listeners.
state = AsyncData(newTodos);
}
서버로 부터 응답이 올시 이를 state에 반영한다.
서버로 부터 응답값이 오지않을시? 해당 데이터가 비지니스 로직에서 치명적인 데이터가 아닐시
로컬환경에서 Optimistic Response을 하여
state = [...newTodos, ...state];의 방식을 사용하기도 한다.
다른 방법으로는 AsyncNotifier를 다시 빌드하기 위해 ref.invalidateSelf();하는 방법을 취한다.
Future<void> addTodo(Todo todo) async {
// We don't care about the API response
await http.post(
Uri.https('your_api.com', '/todos'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(todo.toJson()),
);
// Once the post request is done, we can mark the local cache as dirty.
// This will cause "build" on our notifier to asynchronously be called again,
// and will notify listeners when doing so.
ref.invalidateSelf();
// (Optional) We can then wait for the new state to be computed.
// This ensures "addTodo" does not complete until the new state is available.
await future;
}