Dart cho người mới: 10 khái niệm cần nắm trước khi viết app Flutter


Flutter dùng Dart làm ngôn ngữ duy nhất. Điều này có nghĩa: mọi widget bạn viết, mọi dòng logic bạn xử lý, mọi lỗi bạn gặp khi làm app — cuối cùng đều là câu hỏi về Dart. Người mới thường muốn "nhảy thẳng" vào Flutter vì thấy giao diện đẹp, nhưng chỉ vài buổi là kẹt ở những chỗ như null check operator used on a null value, Future chưa await, hay không hiểu vì sao setState không cập nhật giao diện.
Bài này là bài thứ hai trong series 4 bài về Flutter. Bài trước đã trả lời "có nên học Flutter" và vạch lộ trình 5 giai đoạn; bài này đi sâu vào giai đoạn 1 của lộ trình đó: nền tảng Dart.
Mục tiêu rất cụ thể: sau khi đọc xong và tự tay chạy lại các ví dụ, bạn nắm được 10 khái niệm Dart đủ để đọc hiểu mọi đoạn code Flutter cơ bản — thay vì copy-paste rồi cầu mong nó chạy.
Vì sao phải học Dart trước, không học song song?
Câu trả lời ngắn: vì Flutter không che giấu Dart.
Nếu bạn học React Native, phần lớn thời gian bạn làm việc với JavaScript/TypeScript mà bạn có thể đã biết. Với Flutter, Dart là ngôn ngữ hoàn toàn mới với phần lớn người mới. Khi bạn viết:
[object Object]Đoạn code này chứa ít nhất 6 khái niệm Dart: class, kế thừa (extends), constructor có tên, constructor const, override, và kiểu trả về. Nếu bạn chưa nắm những khái niệm đó, bạn chỉ đang gõ lại ký tự mà người khác viết.
Ngược lại, khi đã nắm Dart, việc học Flutter nhanh hơn hẳn — vì lúc đó bạn chỉ còn phải học một thứ mới: hệ thống widget, chứ không phải hai thứ cùng lúc.
Cách học hiệu quả: đừng đọc hết tài liệu Dart rồi mới làm Flutter. Hãy học 10 khái niệm trong bài này, làm vài bài tập nhỏ trên DartPad, rồi bắt đầu Flutter và quay lại tra cứu Dart khi cần. Vòng lặp "học → làm → tra cứu" luôn nhanh hơn "học hết → làm".
Khái niệm 1: Biến, kiểu dữ liệu và từ khóa khai báo
Dart là ngôn ngữ statically typed nhưng có type inference — nghĩa là bạn có thể khai báo kiểu, hoặc để Dart tự suy ra.
[object Object]Các điểm cần nhớ:
var: Dart tự suy kiểu từ giá trị đầu tiên. Sau đó bạn không thể gán giá trị khác kiểu.var x = 1; x = 'abc';sẽ báo lỗi.final: gán một lần rồi không được thay đổi nữa.finalđược đánh giá lúc chạy (runtime) — ví dụfinal now = DateTime.now();hợp lệ.const: hằng số được đánh giá lúc biên dịch (compile-time).const x = 5;hợp lệ,const now = DateTime.now();không hợp lệ.constgiúp app nhanh hơn vì Dart loại bỏ việc tạo lại đối tượng — đây là lý do bạn thấy rất nhiềuconsttrong code Flutter.dynamic: bỏ kiểm tra kiểu. Chỉ dùng khi bắt buộc (ví dụ dữ liệu JSON chưa biết hình dạng). Lạm dụngdynamiclà nguyên nhân số một của lỗi chỉ xuất hiện khi chạy thật.
Lỗi người mới hay gặp: khai báo var rồi gán lại giá trị khác kiểu, hoặc dùng const với giá trị chỉ biết lúc chạy. Hãy nhớ quy tắc: mặc định final, dùng const khi có thể, hạn chế var, tránh dynamic.
Khái niệm 2: Null safety — phần quan trọng nhất
Dart có null safety: biến bình thường không được phép null.
[object Object]Ba toán tử bạn sẽ gặp mỗi ngày:
[object Object]Ngoài ra còn late cho biến sẽ được gán sau khi khai báo:
[object Object]Vì sao phần này quan trọng với Flutter: rất nhiều widget nhận tham số có thể null (TextEditingController?, VoidCallback?, String? errorText). Khi đọc code Flutter, bạn sẽ thấy ? và ! khắp nơi. Hiểu null safety giúp bạn đọc được code, và quan trọng hơn là tránh làm app crash.
Quy tắc vàng: ! là lời hứa với trình biên dịch. Chỉ dùng khi bạn thật sự chắc chắn. Gặp lỗi Null check operator used on a null value — nghĩa là lời hứa đó sai, và cách sửa thường không phải là thêm ! mà là xử lý nhánh null bằng ?? hoặc if (x != null).
Khái niệm 3: Hàm, tham số và closures
Dart coi hàm là đối tượng hạng nhất (first-class object) — hàm có thể truyền như tham số, trả về từ hàm khác.
[object Object]Điểm cần nhớ: named parameters là kiểu tham số bạn gặp nhiều nhất khi đọc code Flutter (required, giá trị mặc định). Constructor của widget cũng dùng chính cơ chế này, nên hiểu hàm = hiểu widget.
Khái niệm 4: Collections — List, Set, Map và các thao tác chuỗi
Ba kiểu dữ liệu bạn dùng hằng ngày:
[object Object]Trong Flutter, bạn càng gặp nhiều cấu trúc lồng nhau (ví dụ danh sách tin nhắn trong từng cuộc hội thoại) nên các hàm map, where, fold, any, every, firstWhere sẽ xuất hiện liên tục. Nắm chúng giúp bạn biến dữ liệu API thành giao diện nhanh gọn.
Lỗi hay gặp: sửa danh sách trong lúc đang duyệt (ConcurrentModificationError), hoặc quên .toList() nên nhận về Iterable rồi không dùng được các hàm của List. Ghi nhớ: các hàm như where/map trả Iterable — lazy, muốn dùng ngay thì .toList().
Khái niệm 5: Class, constructor, field và method
Flutter là widget-based, và widget là class. Đây là khái niệm bạn gặp ở 100% file Flutter.
[object Object]Hai điều cốt lõi luôn gặp trong Flutter:
required this.x— cách viết tắt của "tham số có tên, gán thẳng vào field". Bạn thấy nó ở mọi widget.@override+build()— widgetStatelessWidgetvàStatefulWidgetbắt bạn overridebuild. Đây là lý do đầu tiên bạn phải hiểu class, kế thừa trong Dart.
Vì sao Flutter chuộng đối tượng bất biến (immutable) và copyWith
Trong ví dụ trên, NguoiDung không có setter — muốn "đổi tuổi" bạn tạo đối tượng mới. Đây không phải ngẫu nhiên mà là chủ ý của Flutter: widget là bất biến.
Lý do rất thực tế: Flutter so sánh widget cũ và widget mới để quyết định có cần vẽ lại không. Nếu widget có thể bị sửa ở bất kỳ đâu, việc so sánh mất ý nghĩa và app dễ sinh bug "giao diện không cập nhật". Vì vậy bạn sẽ gặp liên tục mẫu:
[object Object]Thói quen nên tập ngay: field final, tạo đối tượng mới thay vì sửa tại chỗ. Đây là gốc rễ của cách làm việc với mọi thư viện quản lý trạng thái trong Flutter.
Khái niệm 6: Kế thừa, abstract và mixin
Ba cách tái sử dụng code trong Dart:
[object Object]Trong Flutter bạn đã gặp cả ba: extends StatelessWidget, implements TickerProvider, with SingleTickerProviderStateMixin. Hiểu sự khác nhau giúp bạn không bối rối khi phải chọn cái nào — quy tắc đơn giản: extends khi là quan hệ "là một loại", mixin khi muốn thêm khả năng, và chỉ dùng implements khi bạn muốn tuân theo một interface.
Khái niệm 7: Enum, records và pattern matching (Dart 3)
Dart 3 mang đến switch mạnh hơn nhiều so với trước đây.
[object Object]Vì sao cần biết: code Flutter hiện đại dùng switch expression cho trạng thái (loading / success / error) rất nhiều. Đây cũng là cách viết gọn, ít lỗi hơn chuỗi if-else dài.
Khái niệm 8: Async, Future và Stream
Đây là khái niệm quyết định bạn có làm được app gọi API hay không.
[object Object]Quy tắc dễ nhớ:
asyncđánh dấu hàm bất đồng bộ; hàmasyncluôn trả vềFuture.await= "dừng ở đây chờ xong rồi chạy tiếp", chỉ dùng được trong hàmasync.- Không
awaitthì bạn nhận vềFuturechứ không phải giá trị — đây là lỗi phổ biến nhất khi mới làm việc với API.
Về Stream: khi dữ liệu đến nhiều lần theo thời gian (socket, chat, vị trí) thì dùng Stream thay vì Future.
[object Object]Lỗi hay gặp: gọi API, set state trước khi có dữ liệu; hoặc quên xử lý lỗi mạng khiến app hiện màn hình trắng. Nên luôn bọc try/catch và luôn có trạng thái báo cho người dùng: đang tải, thành công, lỗi.
Nơi async gặp giao diện: FutureBuilder và StreamBuilder
Hiểu Future là điều kiện để hiểu hai widget quan trọng nhất khi làm app có dữ liệu thật:
[object Object]Ba sai lầm kinh điển khi mới dùng FutureBuilder:
- Gọi API trực tiếp trong
build()(future: layDuLieu()) → mỗi lần vẽ lại là một lần gọi mạng. Hãy tạoFuturemột lần tronginitStaterồi truyền vào. - Quên xử lý
hasError→ app sập hoặc trắng màn hình khi mất mạng. - Truyền
Futuremới mỗi lần rebuild → giao diện nhấp nháy liên tục.
Với dữ liệu đến nhiều lần (chat, tỷ giá, tiến trình tải), bạn dùng StreamBuilder cùng nguyên tắc: xử lý connectionState, lỗi, và dữ liệu rỗng trước khi render.
Khái niệm 9: Generics — vì sao bạn thấy <T> khắp nơi
[object Object]Generics giúp code an toàn kiểu và tái sử dụng. Trong Flutter bạn gặp liên tục: Future<List<SanPham>>, ValueNotifier<int>, List<Widget>, Provider.of<GioHang>(context). Đọc được generics nghĩa là bạn biết dữ liệu đang chảy qua app có hình dạng gì — kỹ năng bắt buộc khi làm việc với API.
Khái niệm 10: Xử lý lỗi và kiểm tra dữ liệu vào
[object Object]Người mới thường để lỗi "nổi lên" rồi app crash hoặc hiện màn hình đỏ. Ba thói quen nên tập từ đầu:
- Kiểm tra dữ liệu vào ngay tại biên (form, API response) thay vì rải
ifkhắp nơi. - Bắt lỗi có mục đích — bắt loại lỗi cụ thể (
on FormatException) để xử lý đúng. - Đừng bao giờ để người dùng thấy lỗi thô. Hiển thị thông báo hiểu được, còn chi tiết kỹ thuật chỉ ghi log.
7 lỗi Dart người mới hay gặp nhất và cách sửa
Đây là các lỗi bạn sẽ gặp trong 2 tuần đầu, kèm cách sửa đúng:
1. Null check operator used on a null value
Nguyên nhân: bạn dùng ! trên giá trị đang null. Cách sửa không phải là thêm ! mà là xử lý nhánh null:
[object Object]2. Quên await khi gọi API
Bạn nhận về Future<List<...>> thay vì List<...>, sau đó gọi .length báo lỗi hoặc in ra Instance of 'Future'. Cách sửa: await trong hàm async, và nhớ hàm gọi nó cũng phải async.
3. setState() called after dispose()
Gọi API xong nhưng người dùng đã rời màn hình. Cách sửa: kiểm tra trước khi set state:
[object Object]4. Sửa list trong lúc đang duyệt → ConcurrentModificationError
Không xoá phần tử trực tiếp trong for. Cách sửa: duyệt trên bản sao [...ds], hoặc dùng ds.where(...).toList().
5. type 'int' is not a subtype of type 'double'
Thường đến từ JSON: server trả 2 nhưng model khai báo double. Cách sửa: chuẩn hoá khi parse, ví dụ (json['gia'] as num).toDouble().
6. const với giá trị không phải hằngconst x = DateTime.now(); không hợp lệ. Dùng final cho giá trị chỉ biết lúc chạy.
7. Lạm dụng dynamic
Code chạy được lúc thử nhưng lỗi khi gặp dữ liệu khác. Cách sửa: khai báo model có kiểu rõ ràng (class SanPham { final String ten; ... }) và parse JSON thành model, thay vì dùng Map<String, dynamic> khắp nơi.
Luyện tập: 5 bài tập Dart nhỏ nên làm trước khi học Flutter
Lý thuyết không đủ. Làm 5 bài này trên DartPad — mỗi bài 15–30 phút:
- Máy tính điểm trung bình: nhập danh sách điểm, tính trung bình, in xếp loại. Luyện: List, hàm,
fold. - Quản lý danh bạ bằng Map: thêm, tìm theo tên, xoá. Luyện: Map, null safety (
?,??). - Mô phỏng gọi API: viết hàm
asynctrả vềFuture<List<String>>sau 1 giây, bắt lỗi khi rỗng. Luyện:Future,try/catch,async/await. - Class sản phẩm: có
finalfield, constructorrequired, methodgiảmGiá(). Luyện: class, immutable,const. - Xử lý chuỗi trạng thái bằng
switchexpression cho 4 trạng thái đơn hàng. Luyện: enum, pattern matching.
Làm hết 5 bài này, bạn sẽ đọc code Flutter cơ bản mà không bị chặn ở phần ngôn ngữ nữa.
Bản đồ: khái niệm Dart này bạn gặp ở đâu trong Flutter
Bảng dưới đây giúp bạn thấy ngay mối liên hệ — khi đọc code Flutter, bạn sẽ nhận ra mình đang nhìn khái niệm nào:
| Khái niệm Dart | Bạn gặp ở đâu trong Flutter |
|---|---|
final / const |
Constructor widget (const Text('...')), hằng số màu, style dùng chung |
Null safety (?, ??) |
Tham số widget có thể bỏ trống, model từ API, xử lý dữ liệu thiếu |
| Named parameters | Mọi widget: Text('x', style: ..., textAlign: ...) |
| List / Map | ListView.builder, dựng danh mục, map dữ liệu JSON → model |
Class + extends |
class HomePage extends StatelessWidget |
@override + build() |
Bắt buộc với mọi widget bạn tự viết |
| Mixin | with SingleTickerProviderStateMixin khi làm animation |
Enum + switch |
Trạng thái màn hình (loading / success / error), trạng thái đơn hàng |
Future + async/await |
Gọi API, đọc/ghi dữ liệu cục bộ, chờ quyền truy cập |
FutureBuilder / StreamBuilder |
Màn hình có dữ liệu từ mạng, danh sách chat |
Generics <T> |
Future<List<SanPham>>, ValueNotifier<int>, Provider.of<GioHang> |
| Xử lý lỗi | Bắt lỗi mạng, validate form, hiển thị thông báo |
Khi đã nhìn bảng này và thấy quen, bạn đã sẵn sàng học Widget ở bài 3.
Kết luận và bước tiếp theo
10 khái niệm trên không cần học thuộc. Điều bạn cần là nhận diện chúng khi đọc code, và biết tra cứu khi viết. Với nền Dart này, bạn có thể bắt đầu giai đoạn 2 của lộ trình: widget và giao diện.
Ba việc nên làm ngay sau bài này:
- Làm 5 bài tập Dart ở trên — đừng bỏ qua, đây là phần tạo khác biệt.
- Đọc lại bài mở đầu series nếu bạn chưa chốt lộ trình: Có nên học Flutter 2026? Lộ trình khóa học lập trình Flutter.
- Cài đặt môi trường theo hướng dẫn Cài đặt Flutter trên Windows, macOS, Linux chi tiết từng bước để sẵn sàng cho bài 3.
Bài 3 của series sẽ trả lời: Widget trong Flutter là gì? Hiểu StatelessWidget và StatefulWidget — trong đó mọi khái niệm Dart ở bài này sẽ được dùng lại ngay. Nếu muốn học có người sửa bài và làm dự án thật, bạn có thể xem khóa học Flutter thực chiến hoặc lịch khai giảng.
Câu hỏi thường gặp
Học Dart mất bao lâu?
Nếu mỗi ngày 1–2 giờ và có làm bài tập, khoảng 1–2 tuần là đủ để đọc hiểu code Dart cơ bản và bắt đầu Flutter. Phần async và Stream thường cần thêm thời gian vì phải gặp tình huống thực tế mới thấm.
Có cần học hết Dart rồi mới làm Flutter không?
Không. Học 10 khái niệm cốt lõi trong bài này, làm bài tập, rồi bắt đầu Flutter. Những phần nâng cao (isolate, FFI, thư viện nâng cao) học sau khi đã có app chạy được.
Dart có khó hơn JavaScript không?
Với người đã biết JavaScript hoặc TypeScript, Dart khá quen: cú pháp gần giống, có class và async/await. Điểm mới chính là null safety và kiểu tĩnh — hai thứ này ban đầu gây cảm giác "khắt khe" nhưng lại giúp giảm lỗi khi app lớn.
Không biết lập trình có học Dart được không?
Được, nhưng nên bắt đầu từ tư duy lập trình cơ bản (biến, điều kiện, vòng lặp, hàm). 10 khái niệm trong bài này chính là phần nền bạn cần, chỉ khác là phải chạy code nhiều hơn thay vì đọc.
Nên dùng DartPad hay cài Flutter để luyện Dart?
Giai đoạn học khái niệm nên dùng DartPad — không cần cài gì, chạy được ngay. Khi chuyển sang Flutter mới cần cài SDK.
const và final khác nhau chỗ nào, khi nào dùng cái nào?
final gán một lần, giá trị được xác định lúc chạy — ví dụ final now = DateTime.now();. const là hằng số biết trước lúc biên dịch — ví dụ const pi = 3.14;, const Text('Xin chào'). Quy tắc: dùng const khi có thể (app nhanh hơn, ít vẽ lại), còn lại dùng final. Hạn chế var, và tránh dynamic trừ trường hợp bắt buộc.
Dart có phải là ngôn ngữ hướng đối tượng? Có cần biết OOP trước không?
Dart là ngôn ngữ hướng đối tượng — mọi thứ, kể cả hàm và số, đều là đối tượng. Bạn không cần học OOP hàn lâm trước, nhưng cần nắm 4 thứ: class, field, method, kế thừa. Trong bài này, khái niệm 5, 6 và 9 chính là phần OOP tối thiểu đủ dùng cho Flutter.
Bao giờ thì nên chuyển từ học Dart sang làm dự án thật?
Khi bạn làm xong 5 bài tập ở trên và đọc hiểu một file widget StatefulWidget bất kỳ mà không cần tra cứu cú pháp. Lúc đó hãy làm ngay một app nhỏ có 3–4 màn hình và gọi 1 API thật — làm dự án là cách học nhanh nhất, nhanh hơn nhiều so với xem thêm video.
Series 4 bài học Flutter cho người mới
- Có nên học Flutter năm 2026? Lộ trình khóa học lập trình Flutter
- Dart cho người mới: 10 khái niệm cần nắm trước khi viết app Flutter (bài này)
- Widget trong Flutter là gì? Hiểu StatelessWidget và StatefulWidget
- Tích hợp Gemini AI vào app Flutter bằng ví dụ thực tế
Bài viết liên quan
Widget trong Flutter là gì? Hiểu StatelessWidget và StatefulWidget
Widget trong Flutter là gì? Phân biệt StatelessWidget và StatefulWidget, vòng đời State, dùng setState đúng cách và khi nào chọn loại nào — có ví dụ code.
Có nên học Flutter 2026? Lộ trình khóa học lập trình Flutter
Flutter có đáng học năm 2026 không? Phân tích ưu nhược điểm, ai nên học và lộ trình 5 giai đoạn từ con số 0 đến app thật trên Store.
Flutter có thể áp dụng trong các ngành công nghiệp khác nhau không
Flutter có thể áp dụng trong các ngành công nghiệp khác nhau không
