View, Component & Screen
Chương trước, ta đã xây dựng View Primitives — những View đơn giản, không biết về feature nào dùng nó. Chương này nâng cấp thêm: phân loại View thành 3 loại và hiểu cách kết nối chúng với business logic.
1. Ba loại View
Phần tiêu đề “1. Ba loại View”View Primitives
Phần tiêu đề “View Primitives”Là View đơn giản, ít hoặc không có logic:
- Label, Button, Image, Avatar
- Không biết về feature nào đang dùng nó
- Có thể sống trong shared UI library
View Components
Phần tiêu đề “View Components”Là View “thông minh hơn” — có state và/hoặc binding:
- Navigation bar, Date picker, Color picker,
SelectionView - Quản lý internal state (ví dụ: item nào đang selected)
- Vẫn không biết về feature cụ thể → cũng có thể sống trong UI library
Ví dụ: SelectionView — hiển thị list, track selected items, handle tap events. Phức tạp hơn một Button, nên phân loại là View Component.
Feature Views
Phần tiêu đề “Feature Views”Là View gắn liền với business logic:
CourseView— hiển thị toàn bộ màn hình khóa học- Biết về data model (
Course,Tutor) - Không reusable cho feature khác — và điều đó OK
UI Library │ Feature-specific─────────────────────┼──────────────────View Primitives │View Components │ Feature Views │ (CourseView)2. Local Components
Phần tiêu đề “2. Local Components”Không phải View Component nào cũng cần sống trong shared UI library. Một số chỉ phục vụ một feature:
Ví dụ: ScheduleView (hiển thị lịch 1-on-1 sắp tới) chỉ dùng trong Course feature. Ta đặt nó trong folder của feature, nhưng vẫn giữ nó self-contained — không depend vào Course model.
Lợi ích: Nếu sau này feature khác cần View này, chỉ cần move nó sang UI library — không cần sửa code.
3. Kết nối View với Business Logic
Phần tiêu đề “3. Kết nối View với Business Logic”Feature View là nơi UI meets business logic. Có nhiều cách kết nối:
Truyền trực tiếp
Phần tiêu đề “Truyền trực tiếp”struct CourseView: View { let course: Course
var body: some View { ThumbDescriptionView( title: course.tutor.name, description: course.tutor.handle ) }}Qua ViewModel
Phần tiêu đề “Qua ViewModel”Khi cần transform data phức tạp hoặc combine nhiều data source:
class CourseViewModel: ObservableObject { @Published var tutorName: String = "" @Published var schedule: [Event] = []
func loadCourse() async { ... }}Khi nào cần ViewModel?
Phần tiêu đề “Khi nào cần ViewModel?”Dùng ViewModel khi:
- Cần transform data phức tạp trước khi display
- Cần lifecycle management — đặc biệt trên Android (
ViewModelsurvive configuration changes) - Nhiều View share cùng state
Không cần ViewModel khi:
- Data đơn giản, truyền thẳng vào View là đủ
- Thêm ViewModel chỉ tăng complexity mà không có benefit
4. “Screen” không phải lúc nào cũng full-screen
Phần tiêu đề “4. “Screen” không phải lúc nào cũng full-screen”Trong daily discussion, ta gọi full-screen view là “screen”. Nhưng kỹ thuật:
- Trên phone,
CourseViewchiếm cả screen. - Trên tablet,
CourseViewcó thể chỉ chiếm một nửa — nửa còn lại là View khác. - Một “screen” trên phone có thể là small component trên tablet.
Takeaway: Khi discuss design, dùng từ “screen” là OK. Nhưng khi code, hãy nghĩ theo feature — không quan trọng View chiếm bao nhiêu pixel.
Kết luận: Phân loại View thành 3 loại (Primitives, Components, Feature Views) giúp bạn biết View nào nên ở đâu, cần bao nhiêu logic, và liệu có reusable không.