Bảng Điều Khiển Ôn Tập Android
Kotlin • MVVM • Flow • REST API • Compose • Testing
Tuần 3 — TypeScript hướng đối tượng + React Native
Tạo và chạy được ứng dụng React Native đầu tiên trên điện thoại thật qua Expo Go (Android & iOS).
1Ngày 1 — Class & object trong TypeScript
Ghi nhớ
Mục tiêu: khai báo được class với constructor, thuộc tính, phương thức và tạo object từ class đó.
Class là một khuôn mẫu mô tả một loại đối tượng: nó có những thuộc tính (property) gì và làm được những việc (method) gì. Object là một thực thể cụ thể được tạo ra từ class đó, gọi là một instance.
Class NguoiDung
class NguoiDung {
ten: string;
tuoi: number;
constructor(ten: string, tuoi: number) {
this.ten = ten;
this.tuoi = tuoi;
}
gioiThieu(): string {
return `Tôi tên ${this.ten}, ${this.tuoi} tuổi.`;
}
}
const minh = new NguoiDung("Minh", 25);
console.log(minh.gioiThieu());Mẹo
Ví dụ so sánh: class giống như bản thiết kế một mẫu nhà; object là từng căn nhà cụ thể được xây theo bản thiết kế đó — có thể xây nhiều căn (nhiều object) từ cùng một bản thiết kế (một class).
- Bài tập 1: Viết class Sach có thuộc tính tieuDe, tacGia và method moTa() trả về một câu giới thiệu sách.
- Bài tập 2: Tạo 2 object Sach khác nhau từ class trên và in ra mô tả của cả hai.
Lưu ý
Lỗi thường gặp: quên viết this. khi truy cập thuộc tính bên trong method của class — this luôn cần để chỉ đúng object đang được thao tác.
- Tự kiểm tra: Class và object khác nhau ở điểm nào?
- Tự kiểm tra: constructor dùng để làm gì?
2Ngày 2 — Interface, kế thừa & composition
Ghi nhớ
Mục tiêu: dùng interface cho class, hiểu kế thừa (extends) và khi nào nên dùng composition thay vì kế thừa.
Một class có thể cam kết tuân theo một interface bằng từ khoá implements — nghĩa là class đó bắt buộc phải có đủ các thuộc tính/phương thức mà interface yêu cầu.
interface + implements
interface CoTheGioiThieu {
gioiThieu(): string;
}
class NhanVien implements CoTheGioiThieu {
constructor(public ten: string, public chucVu: string) {}
gioiThieu(): string {
return `${this.ten} làm ${this.chucVu}`;
}
}Kế thừa (extends) cho một class con dùng lại thuộc tính/phương thức của class cha, đồng thời có thể thêm hoặc ghi đè (override) hành vi riêng. Composition là cách gộp các object nhỏ lại thành một object lớn hơn (object này 'có một' object khác) thay vì bắt nó phải kế thừa.
Kế thừa (extends)
class NhanVienQuanLy extends NhanVien {
constructor(ten: string, public soNhanVien: number) {
super(ten, "Quản lý");
}
}Mẹo
Quy tắc chọn nhanh: dùng kế thừa khi quan hệ thật sự là 'là một' (NhanVienQuanLy là một NhanVien). Dùng composition khi quan hệ là 'có một' (một Xe có một DongCo) — composition thường linh hoạt và dễ bảo trì hơn khi hệ thống lớn dần.
- Bài tập 1: Viết interface CoTheKeu với method keu(), cho 2 class ChoCon và MeoCon cùng implements interface đó với nội dung keu() khác nhau.
- Bài tập 2: Viết class XeMay có thuộc tính dongCo là một object DongCo riêng (composition) thay vì kế thừa.
Lưu ý
Lỗi thường gặp: lạm dụng kế thừa nhiều tầng (class A kế thừa B, B kế thừa C...) khiến code khó theo dõi và dễ vỡ khi sửa class cha; nên ưu tiên composition khi không chắc chắn.
- Tự kiểm tra: implements dùng để làm gì?
- Tự kiểm tra: Khi nào nên dùng kế thừa, khi nào nên dùng composition?
3Ngày 3 — Union type, enum & generic cơ bản
Ghi nhớ
Mục tiêu: dùng được union type và enum để mô tả một tập giá trị cố định, hiểu generic ở mức cơ bản.
Union type mô tả một biến chỉ có thể nhận một trong vài giá trị cụ thể, nối bằng dấu |. Đây chính là nền tảng để mô tả trạng thái màn hình (UI state) mà bạn sẽ dùng nhiều ở Tuần 5: một màn hình chỉ có thể đang loading, đã success, hoặc bị error.
Union type cho UI state
type TrangThai = "loading" | "success" | "error";
function hienThi(trangThai: TrangThai): string {
if (trangThai === "loading") return "Đang tải...";
if (trangThai === "success") return "Xong!";
return "Có lỗi xảy ra";
}enum cũng dùng để gom một tập giá trị cố định, có tên gọi rõ ràng, hay dùng khi tập giá trị đó có ý nghĩa cụ thể (ví dụ các vai trò người dùng).
enum vai trò người dùng
enum VaiTro {
Admin = "admin",
KhachHang = "khach_hang",
}
const vaiTro: VaiTro = VaiTro.KhachHang;Generic cho phép viết một function/type dùng chung được cho nhiều kiểu dữ liệu khác nhau, thay vì phải viết lặp lại cho từng kiểu. <T> là một 'kiểu ẩn danh' sẽ được xác định cụ thể mỗi lần gọi.
Generic function cơ bản
function phanTuDauTien<T>(danhSach: T[]): T {
return danhSach[0];
}
console.log(phanTuDauTien<number>([1, 2, 3])); // 1
console.log(phanTuDauTien<string>(["a", "b"])); // "a"- Bài tập 1: Viết union type PhuongTien = "xe_may" | "o_to" | "xe_dap" và một function nhận vào rồi in ra tên tiếng Việt tương ứng.
- Bài tập 2: Viết enum MucDoUuTien với 3 giá trị Thap/TrungBinh/Cao.
Lưu ý
Lỗi thường gặp: khai báo kiểu any thay vì union type/interface cụ thể vì ngại nghĩ hết các trường hợp — làm vậy TypeScript không còn bắt lỗi giúp bạn được nữa.
- Tự kiểm tra: Union type khác gì so với việc chỉ dùng string thông thường?
- Tự kiểm tra: Generic dùng để giải quyết vấn đề gì?
4Ngày 4 — React cơ bản: component, JSX, props
Ghi nhớ
Mục tiêu: hiểu component là gì, viết được component nhận props, hiểu vì sao UI trong React được mô tả khai báo (declarative).
Trong React (và React Native), giao diện được chia thành các component — mỗi component là một function trả về mô tả giao diện bằng JSX (cú pháp giống HTML viết ngay trong TypeScript). Nhiều component nhỏ ghép lại tạo thành một màn hình lớn.
Component nhận props
type LoiChaoProps = {
ten: string;
};
function LoiChao({ ten }: LoiChaoProps) {
return <Text>Xin chào, {ten}!</Text>;
}
// Dùng lại: <LoiChao ten="Minh" />Props là dữ liệu được truyền từ component cha xuống component con, giống như tham số của một function. Component con không tự sửa props của mình, chỉ hiển thị dựa trên props nhận được.
Mẹo
Declarative (khai báo) nghĩa là bạn mô tả giao diện 'nên trông như thế nào' ứng với một dữ liệu cho trước, thay vì ra lệnh từng bước 'vẽ cái này, rồi xoá cái kia' (imperative). React tự lo phần cập nhật màn hình khi dữ liệu đổi.
- Bài tập 1: Viết component ThongTinSach nhận props tieuDe và tacGia, hiển thị bằng hai dòng Text.
- Bài tập 2: Dùng lại component đó 3 lần với 3 props khác nhau.
Lưu ý
Lỗi thường gặp: quên khai báo type cho props (hoặc quên destructure props trong tham số function) khiến TypeScript báo lỗi hoặc component nhận props sai vị trí.
- Tự kiểm tra: Component là gì? Props dùng để làm gì?
- Tự kiểm tra: Declarative khác imperative ở điểm nào?
5Ngày 5 — Cài Node.js/Expo & tạo project React Native đầu tiên
Ghi nhớ
Mục tiêu: cài Expo CLI và tạo được project React Native đầu tiên, hiểu cấu trúc project cơ bản.
Expo là một bộ công cụ giúp tạo và chạy app React Native mà không cần cài Android Studio hay Xcode ngay từ đầu — bạn có thể chạy thử app trên điện thoại thật qua ứng dụng Expo Go (sẽ dùng ở Ngày 6). Khi nào cần build app thật để phát hành, Expo cung cấp dịch vụ EAS Build (sẽ học ở Tuần 8).
- 1. Đảm bảo Node.js đã cài từ Tuần 2 (kiểm tra bằng lệnh node -v).
- 2. Chạy lệnh npx create-expo-app ten-du-an để tạo project mới (npx tự tải Expo CLI khi cần, không cần cài riêng).
- 3. Vào thư mục project vừa tạo bằng lệnh cd ten-du-an.
Sau khi tạo xong, project có sẵn một số file quan trọng: App.tsx là màn hình gốc của app; package.json liệt kê các thư viện project dùng; thư mục assets chứa hình ảnh/icon. Đây là những file bạn sẽ chỉnh sửa nhiều nhất trong các tuần tới.
- Bài tập 1: Cài đặt và tạo một project tên hoc-react-native bằng create-expo-app.
- Bài tập 2: Mở file App.tsx, đọc và đoán xem đoạn code mặc định đang hiển thị gì trên màn hình.
Lưu ý
Lỗi thường gặp: dùng bản Node.js quá cũ hoặc thiếu quyền ghi thư mục (npm permission) khiến lệnh create-expo-app báo lỗi giữa chừng — nên cài bản Node.js LTS mới nhất.
- Tự kiểm tra: Vì sao người mới nên bắt đầu bằng Expo thay vì React Native CLI thuần?
- Tự kiểm tra: File App.tsx dùng để làm gì trong project?
6Ngày 6 — Chạy app trên Expo Go (điện thoại thật) & simulator
Ghi nhớ
Mục tiêu: chạy được project vừa tạo trên điện thoại thật qua Expo Go, hiểu khi nào cần dùng thêm simulator/emulator.
Expo Go là một app có sẵn trên Google Play và App Store, cho phép mở thử project Expo của bạn ngay trên điện thoại thật mà không cần build/cài riêng. Chạy lệnh npx expo start trong thư mục project sẽ hiện một mã QR; quét mã đó bằng app Expo Go (điện thoại và máy tính cần chung một mạng Wi-Fi) để mở app.
Simulator (cho iOS, chạy trên máy Mac) và emulator (cho Android, chạy trên máy tính) là điện thoại giả lập trên máy tính, hữu ích khi không có sẵn điện thoại thật hoặc cần thử nhiều kích thước màn hình khác nhau cùng lúc.
Mẹo
Nên ưu tiên thử trên điện thoại thật khi có thể — nó cho đúng cảm giác thật về cảm ứng, kích thước và hiệu năng, những thứ mà simulator/emulator không mô phỏng chính xác 100%.
- Bài tập 1: Cài Expo Go trên điện thoại, chạy npx expo start và mở thử project Ngày 5 qua quét QR.
- Bài tập 2: Sửa một dòng chữ trong App.tsx, lưu file, quan sát app trên điện thoại tự cập nhật ngay (fast refresh).
Lưu ý
Lỗi thường gặp: điện thoại và máy tính không cùng mạng Wi-Fi (hoặc mạng công ty chặn kết nối giữa các thiết bị) khiến quét QR mãi không mở được app — thử đổi sang cùng Wi-Fi nhà hoặc dùng chế độ kết nối qua tunnel của Expo.
- Tự kiểm tra: Expo Go dùng để làm gì?
- Tự kiểm tra: Vì sao nên thử trên điện thoại thật thay vì chỉ dùng simulator/emulator?
7Ngày 7 — Thêm nút, xử lý sự kiện, đọc log & ôn tập
Ghi nhớ
Mục tiêu: thêm được nút bấm xử lý sự kiện bằng onPress, đổi được state khi bấm, và đọc log khi có lỗi; ôn lại cả tuần.
Pressable (hoặc Button) là component tạo vùng bấm được. Thuộc tính onPress nhận vào một function sẽ chạy mỗi khi người dùng bấm vào — giống lambda bạn gán cho một sự kiện.
Đếm số lần bấm nút bằng useState
import { useState } from "react";
import { Pressable, Text, View } from "react-native";
function DemSoLan() {
const [soLan, setSoLan] = useState(0);
return (
<View>
<Text>Đã bấm {soLan} lần</Text>
<Pressable onPress={() => setSoLan(soLan + 1)}>
<Text>Bấm vào đây</Text>
</Pressable>
</View>
);
}Đọc ý chính: Text hiển thị chữ; Pressable với onPress={...} là một arrow function chạy MỖI khi bấm (nhớ arrow function ở Ngày 4-5 tuần trước); useState(0) tạo một state ban đầu là 0, setSoLan(...) cập nhật state đó và khiến màn hình tự vẽ lại. Chi tiết state sẽ học sâu hơn ở Tuần 4-5.
Khi app có lỗi hoặc chạy sai, cửa sổ terminal đang chạy npx expo start sẽ hiện log — thông tin giúp bạn 'nhìn vào bên trong' app. Dùng console.log(...) để tự in thêm thông tin cần kiểm tra, rồi đọc lại trong log đó.
Mẹo
Khi app chạy sai hoặc bị lỗi đỏ (red screen), việc đầu tiên là đọc kỹ dòng thông báo lỗi trong log — nó thường chỉ đúng file và dòng gây lỗi. Đây là kỹ năng debug quan trọng nhất khi mới học.
- Bài tập 1: Sửa dòng chữ mặc định trên màn hình thành tên của bạn, lưu và xem app tự cập nhật.
- Bài tập 2 (sản phẩm cuối tuần): Làm app đếm số lần bấm nút, hoặc app tính tuổi (nhập năm sinh, bấm nút hiện tuổi), chạy được trên điện thoại thật qua Expo Go.
- Bài tập 3: Thêm một console.log trong onPress và xem nó hiện trong log terminal.
Lưu ý
Lỗi thường gặp: chỉ đổi một biến thường (không qua setSoLan/setState) nên giá trị có đổi trong code nhưng màn hình không tự vẽ lại — React chỉ vẽ lại khi state được cập nhật qua hàm set tương ứng.
- Ôn tập tuần: class, interface, kế thừa và composition dùng khi nào.
- Ôn tập tuần: union type và enum giải quyết vấn đề gì.
- Ôn tập tuần: component, JSX, props là gì; declarative nghĩa là sao.
- Ôn tập tuần: Các bước tạo và chạy một project React Native đầu tiên qua Expo Go; vì sao cần đọc log khi debug.
Checklist theo dõi