티스토리 뷰

View

View는 유저에게 UI를 보여주는 곳으로,  View 클래스 하나로 이루어져 있다. 

Flutter에서는  선언형 UI를 사용한다. 그래서 모든 View의 구성요소들은 Widget이 되고, 이것들의 위젯트리를 만들어 화면을 표시하게 된다. 

기반이 되는 대표 Widget으로 StatefulWidget과 StatelessWidget이 있다.

StatefulWidget은 자체적으로 state를 유지하고 관리하기 때문에  커스텀 위젯을 만드는데 주로 사용하는 편이다.

우리처럼 ViewModel에서 state를 관리할 경우에는 StatelessWidget으로 View를 만드는 것이 개념적으로 바람직 하다.

PostListView (post/post_list_view.dart)

게시물 목록을 표시하는 View

/// 게시물 목록 View
class PostListView extends StatelessWidget {
  late PostListViewModel viewModel;

  @override
  Widget build(BuildContext context) {
    viewModel = Provider.of<PostListViewModel>(context); // Provider로 viewModel을 가져온다.
    return Scaffold(
      appBar: AppBar(title: Text('Post List')),
      body: _buildPostList(),
    );
  }

  Widget _buildPostList() {
    final items = viewModel.items;     // viewModel에 저장된 items
    final itemCount = items.length;
    return ListView.builder(
      itemBuilder: (context, index) {
        final item = items[index];
        return ListTile(title: Text(item.title));
      },
      itemCount: itemCount,
    );
  }
}

위 코드는 StatelessWidget이 build될때 View와 연결된 PostListViewModel를 가져와 items를 ListWidget으로 그려주는 예시이다.

ViewModel

ViewModel은  View 단위의 비지니스 로직을 처리하고 View상태를 유지/관리하는 곳으로 ViewModel클래스 하나로 이루어 진다.
우리는 provider을 사용할것이기 때문에 ChangeNotifier을 mixin해서 viewModel을 만든다.

PostListViewMode (post/post_list_viewmodel.dart)

/// 게시물 viewModel
class PostListViewModel with ChangeNotifier {
  late final PostRepository _postRepository;

  List<Post> get items => _items;
  List<Post> _items = [];

  PostListViewModel() {
    _postRepository = PostRepository();
    _loadItems();
  }

  Future<void> _loadItems() async {
    _items = await _postRepository.getItems();
    notifyListeners();
  }
}

viewModel생성시  _loadItems() 함수를 호출하게 되고 이때 게시물 목록을 가져온다.

게시물을 repository에서 가져오는 방법은 async await이기 때문에 비동기로 처리되고, 이 작업이 끝나면 notifyListeners을 호출해서 view가 다시 build되도록 한다.

 

생성자에서 _loadItems() 함수를 호출할때 await  _loadItems()가 아님에 유의 하자 생성자에서 await를 사용할 수 없다.

만약 꼭 사용하고 싶다면 Future(_loadItems) or Future(() => async {await _loadItems();}) 사용해야 한다.

원칙적으로 future함수를 호출할때는 await로 호출해야 하지만 생성자가 _loadItems함수가 끝나기를 기다릴 필요가 없기 때문에 굳이 await로 함수를 호출할 필요가 없다.

await없이 Future 함수를 호출하면 그냥 단순 Future가 반환되고, main 함수는 끝나지만 Future함수의 내부로직은 따로 수행된다.

Provider

view와 viewModel을 만들었지만 이렇게 한다고 서로 연결되는 것은 아니다.
실제 view와 viewModel의 연결을 위해서는 ChangeNotifierProvider를 사용해서 view가 viewModel의 변화를 감지하고 사용할 수 있도록 해주어야 한다.

Page (post/post_pages.dart)

view와 viewModel을 연결시켜주는 page라는 개념을 도입했다. page는 우리가 앱에서 보는 하나의 화면단위라고 이해하면 쉬울것이다.

class PostListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<PostListViewModel>(
        create: (_) => PostListViewModel(),
        child: PostListView());
  }
}

이제 게시물 목록 화면이 완성되었다. 외부에서 이 화면을 호출할때는 PostListPage를 호출하게 되고, 그렇게 되면 PostListView와 PostListViewModel이 생성되어 사용할 수 있게 된다.

 

>  3부 - Data Layer 에서 계속

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함