Async Technique
Reference
본 게시물은 코드팩토리 - Flutter 중급 강의 (opens in a new tab)을 참고해서 만들어졌습니다.
State Notifier With
기존에 데이터를 받아오는 화면은 이런식으로 구성이 되어있었다.
restaurant_screen.dart
// json 데이터에서 data 키 안의 Resstaurant 배열을 가져오는 함수
Future<List<RestaurantModel>> paginateRestaurant({required WidgetRef ref}) async {
final dio = ref.watch(dioProvider);
final CursorPagination<RestaurantModel> resp = await RestaurantRepository(dio, baseUrl: 'http://$ip/restaurant').paginate();
return resp.data;
}
...
중략
...
FutureBuilder(
future: paginateRestaurant(ref: ref),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
return ListView.separated(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final pItem = snapshot.data![index];
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => RestaurantDetailScreen(
id: pItem.id,
),
));
},
child: RestaurantCard.fromModel(model: pItem));
},
separatorBuilder: (context, index) {
return const SizedBox(height: 16.0);
},
);
},
)
위와 같은 방식으로 스크린을 구성하게 되면 데이터를 받고 처리하는 로직을 View에서 구현해줘야하기 때문에 코드가 깔끔하지 못하다.
이를 해결하기위해서 Repository를 StateNotifier를 이용해서 한 번 더 감싸주고 State를 view에서 watch하는 방식으로 변경하면 이 코드가 더 간결해진다.
객체가 생성되자마자 paginate를 실행해주고 state를 통해서 view를 업데이트 해줄 StateNotifier를 만들어준다.
final restaurantProvider = StateNotifierProvider<RestaurantStateNotifier, List<RestaurantModel>>((ref) {
final Dio dio = ref.read(dioProvider);
final RestaurantRepository repository = RestaurantRepository(dio);
return RestaurantStateNotifier(repo: repository);
});
class RestaurantStateNotifier extends StateNotifier<List<RestaurantModel>> {
late final RestaurantRepository _repository;
RestaurantStateNotifier({required RestaurantRepository repo})
: super([]) {
_repository = repo;
paginate();
}
void paginate() async {
CursorPagination<RestaurantModel> resp = await _repository.paginate();
state = resp.data;
}
}