728x90

Flutter Provider로 작성된 상태관리 ViewModel이다.

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
 
class CatViewModel extends ChangeNotifier {
 
  final List<String> _catImages = []; // 고양이 사진을 담을 변수
 
  List<String> _favoriteImages = []; // 좋아요 사진을 담을 변수
 
  List<String> get catImages => _catImages;
 
  List<String> get favoriteImages => _favoriteImages;
 
 Dio _dio = Dio();
 
  // 생성자
  CatViewModel() {
   _dio.interceptors.add(LogInterceptor());
   _dio.interceptors.add(CustLogInterceptor());
    getRandomCatImages();
  }
 
  void getRandomCatImages() async {
    Response resp = await _dio.get(
        'https://api.thecatapi.com/v1/images/search?limit=10&mime_types=jpg');
    print(resp.data);
    for (int i = 0; i < resp.data.length; i++) {
      final map = resp.data[i];
      _catImages.add(map['url']); // url만 추출하여 catImages 에 이미지 추가.
    }
    notifyListeners();
  }
 
  // 좋아요 토글
  void toggleFavoriteImage(String catImage) {
    if (_favoriteImages.contains(catImage)) {
      _favoriteImages.remove(catImage); // 이미 좋아요한 경우 제거
    } else {
      _favoriteImages.add(catImage); // 새로운 사진 추가
    }
 
    notifyListeners(); // 새로고침
  }
}

 

ViewModel 로 클래스명을 정의하기도 하고 Service로 정의하기도 한다.

View 에서 코드를 분리하여 ViewModel에 코드를 대부분 구현하고, View에서는 UI중심으로 코드가 최소화되도록 구현하는 것이 중요하다.

ViewModel 에서는 UI에서 직접적으로 수정할 수 없도록 변수를 선언하는 것이 매우 중요하다.

그래서 위 예제에서는 Class 내부에 있는 변수에 언더바(_)를 붙여서 Private로 정의했고, 외부에서 접근하는 것은 Getter를 추가했다.

기능을 추가할 때 ViewModel 안에 선언한 변수를 외부에서 직접적으로 접근할 수 없도록 신경써야 한다.

 

 

CustLogInterceptor는 Interceptor를 상속받았고 특별하게 코드를 추가한 것은 없다.

아래 코드를 잘 활용하면 유용하게 사용할 수 있다.

import 'package:dio/dio.dart';
 
class CustLogInterceptor extends Interceptor {
 
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    print('REQUEST[${options.method}] => PATH: ${options.path}');
    return super.onRequest(options, handler);
  }
 
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) async {
    print('Response_URI >>> ${response.realUri.toString()}');
    return super.onResponse(response, handler);
  }
 
  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    print(
      'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}',
    );
    return super.onError(err, handler);
  }
}

 

 

HomePage UI 클래스

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomePage extends StatelessWidget {
  const HomePage({super.key});
  @override
  Widget build(BuildContext context) {
    return Consumer<CatViewModel>(
      builder: (context, viewModel, child) {
        return Scaffold(
          body: GridView.count(
            mainAxisSpacing: 8,
            crossAxisSpacing: 8,
            crossAxisCount: 2,
            padding: EdgeInsets.all(8),
            children: List.generate(
              viewModel.catImages.length,
              (index) {
                String catImage = viewModel.catImages[index];
                return GestureDetector(
                  onTap: () {
                    viewModel.toggleFavoriteImage(catImage);  // 사진 클릭시
                  },
                  child: Stack(
                    children: [
                      // 사진
                      Positioned.fill(
                        child: Image.network(
                          catImage,
                          fit: BoxFit.cover,
                        ),
                      ),
                      // 좋아요
                      Positioned(
                        bottom: 8,
                        right: 8,
                        child: Icon(
                          Icons.favorite,
                          color: viewModel.favoriteImages.contains(catImage)
                              ? Colors.amber
                              : Colors.transparent,
                        ),
                      ),
                    ],
                  ),
                );
              },
            ),
          ),
        );
      },
    );
  }
}

 

 

 

'Flutter 앱 > 상태관리' 카테고리의 다른 글

Flutter riverpod 자동 생성  (0) 2024.01.15
Flutter Riverpod 예제 : Bucket List  (0) 2023.12.27
Flutter StatefulWidget  (0) 2023.12.13
Flutter Riverpod - NotifierProvider.family  (0) 2023.12.11
Flutter Riverpod - NotifierProvider  (0) 2023.12.11
블로그 이미지

Link2Me

,