한 페이지에 코드를 짜다보면 정말 정신이 없다. 하지만 코드를 페이지별로 나누고, 기능별로 나누다보면 가독성도 높아지고 수정하고자하는 코드를 빨리 찾을 수 있어 편하다.
아키텍쳐 패턴 중 일반적으로 많이 쓰이는 MVVM 패턴을 적용해서 한 페이지로 빠르게 만든 내 코드를 차근 차근 분리해볼 것이다.
그 전에 model의 개념과 왜 써야하는지를 이해해보자!
코드를 짜다보면 특히 UI를 그릴 때 반복적으로 등장하고 다른 페이지에서도 계속 써야 하는 위젯이 생긴다.
이럴 때 하나의 위젯으로 만들어 필요할 때마다 불러서 사용하면 굉장히 편할 것이다.
이렇게 따로 클래스로 만들어 내면 이 클래스는 데이터를 담은 틀이 되기 때문에 모델이라고 부른다.
아래 예시에서는 CardNews를 만들기 위해 반복적으로 등장하는 imgPath, title, subtitle을 한번에 불러다 쓰기 위해 CardContent 위젯을 따로 뻈다. 이때 CardContent이 바로 모델이 된다.
class CardNews extends StatelessWidget {
const CardNews({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final List<CardContent> cardContentList = [
CardContent(
imgPath: 'assets/images/04_01_cardnews.png',
title: 'test',
subtitle: 'test'),
CardContent(
imgPath: 'assets/images/04_02_cardnews.png',
title: 'test',
subtitle: 'test'),
class CardContent {
final String imgPath;
final String title;
final String subtitle;
CardContent(
{required this.imgPath, required this.title, required this.subtitle});
}
json 으로 네트워크 통신을 해서 데이터를 가져올 때 dart 내에서 사용할 데이터 틀 즉 모델에 맞추기 위해 클래스 안에 fromjson을 추가로 정의한다.
이때 fromjson 메서드를 통해 모델 클래스 내 값들과 json 데이터 값들이 일치된다.
model을 UI에서 사용할 때는 가져온 데이터들을 순회하며 각 요소들을 모델 클래스의 객체로 변환시키는 작업이 추가로 필요하게 된다.
아래 예시는 fromJson 메서드를 통해 일치시키는 작업을 하고, UI에 뿌려주기 전 모델 클래스의 객체로 변환시키는 작업을 했다.
class MovieInfo {
int? userId;
int? id;
String? title;
MovieInfo({this.userId, this.id, this.title});
MovieInfo.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
id = json['id'];
title = json['title'];
}
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
final List<MovieInfo> movieInfoList = [];
@override
void initState() {
getData();
super.initState();
}
Future getData() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums'));
final jsonResult = jsonDecode(response.body);
setState(() {
jsonResult.forEach((e) {
movieInfoList.add(MovieInfo.fromJson(e));
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('영화정보 api 연습'),
),
body: ListView(
children: movieInfoList.map((e) => ListTile(
title: Text(e.title ?? 'error'),
subtitle: Text(e.id.toString()),
),
).toList(),
)