플러터로 개발할 때면 상태관리 패키지 provider, bloc, getx, riverpod 등 다들 많이 들어보셨을 겁니다.
상태 관리 패키지 사용없이 앱을 만들 수 있을까요? 제가 한번 해봤습니다.
1.서두 - 왜 상태관리 패키지를 사용하지 않으셨어요?
새로운 프로젝트가 시작되며 회사에서 제안을 받았고 저 역시도 상태관리 패키지를 사용하지 않고 개발하는 방법에 궁금했기 때문에 승낙했습니다. 회사에서는 기존에 getx를 사용해서 앱개발을 진행하셨고 새로운 프로젝트는 한번 가볍게 가보자 겸 빠르게 진행해보자였기 때문에 상태관리 패키지 없이 개발을 진행하게됐습니다.
2.본문 - 그래서 어떻게 개발하셨어요?
먼저 플러터 버전 3.0.0 다트버전 2.18.0 입니다.
MVC 패턴 사용
필요한 데이터가 있다면 생성자로 전달하면서 개발을 시작했습니다. 그러다가 중간에 설계를 다시 잡게 되었고 NamedRoute로 파일관리를 시작하며 생성자로 전달하는데 한계를 느꼈습니다. 매번 파일 하나 수정하면 타고타고 들어가서 일일이 데이터를 수정해줘야하다보니 내가 맞게 하고있나 하는 의문과 답답한 나날들이었습니다. 하지만 어쩌겠습니까 해야죠🥲
상태관리 패키지 사용하지 않고 개발하는 방법을 주변의 플러터 개발자님들에게 물어물어 InheritedWidget을 만났습니다. 상태관리 패키지를 사용하지 않는다고하면 백이면 백 개발자님들 모두 아니 왜..ㅠ 고생을 사서하시죠 라는 반응을 받았습니다. 다들 그래도 한번쯤 궁금해하셨을 거라고 믿어요🤔
그럼 구글조차 추천하지 않는 InheritedWidget 사용법 간단하게 살펴볼까요?
//1단계 InheritedWidget을 상속받는 PhotoProvider 클래스를 생성합니다. 가장 기본 형태입니다.
import 'package:flutter/material.dart';
class PhotoProvider extends InheritedWidget {
const PhotoProvider({Key? key, required Widget child})
: super(key: key, child: child);
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
// TODO: implement updateShouldNotify
throw UnimplementedError();
}
}
변경될 데이터를 가질 위젯트리 위에 이 위젯 트리 씌울 거에요
import 'package:flutter/material.dart';
import 'package:image_search_app/data/api.dart';
class PhotoProvider extends InheritedWidget {
final PixabayApi api;
const PhotoProvider({
Key? key,
required this.api,
required Widget child,
}) : super(key: key, child: child);
//context에 있는 정보를 제공
static PhotoProvider of(BuildContext context) {
final PhotoProvider? result =
context.dependOnInheritedWidgetOfExactType<PhotoProvider>();
assert(result != null, 'No PixabayApi found in context');
return result!;
}
// 위젯이 변경되면 다시 전달하라는 규칙을 정하는 메서드
@override
bool updateShouldNotify(PhotoProvider oldWidget) {
return oldWidget.api != api;
}
}
// main.dart
import 'package:flutter/material.dart';
import 'package:image_search_app/ui/home_view.dart';
import 'data/api.dart';
import 'data/photo_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PhotoProvider(
api: PixabayApi(),
child: HomeView(),
),
);
}
}
// 이제 실제로 사용해봅니다.
import 'package:flutter/material.dart';
import 'package:image_search_app/data/photo_provider.dart';
import 'package:image_search_app/ui/widget/photo_widget.dart';
import '../model/photo.dart';
class HomeView extends StatefulWidget {
HomeView({Key? key}) : super(key: key);
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final _controller = TextEditingController();
List<Photo> _photos = [];
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// 이렇게 사용할 수 있어요
final photoProvider = PhotoProvider.of(context);
return Scaffold(
appBar: AppBar(title: const Text('이미지 겁색 앱')),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
suffixIcon: IconButton(
onPressed: () async {
final photos =
await photoProvider.api.fetch(_controller.text);
setState(() {
_photos = photos;
});
},
icon: const Icon(Icons.search),
),
),
),
),
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(10),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: _photos.length,
itemBuilder: (context, index) {
final photo = _photos[index];
return PhotoWidget(
photo: photo,
);
},
),
),
],
),
);
}
}
3.결론 - 그래서 상태관리 패키지 없이 할만 하셨어요?
넵! 회사에서는 빠르게 개발해야하던 상황이다보니 주먹구구식으로 진행했지만 개인적으로 공부하게 되다보니 많은 도움이 되었습니다.
하지만 google에서 왜 inheritedWidget을 추천하지 않는지는 아직 잘 모르겠습니다. 패키지가 있으면 그냥 패키지 쓰라는 걸까요??
저는 다음번에 개발할 때도 상태관리 패키지 없이 진행해도 괜찮을 것 같습니다. 하지만 역시 대세는 provider인 것 같습니다.
대형프로젝트에서는 역시 bloc이 꽉 잡고 있다는 생각도 들었습니다.
그러니 선택은 뭐든지 직접 해보시는 걸로 그럼 오늘도 즐코하세요 🙇🏻♀️