Component đầu tiên bạn viết thường ổn: một cái dashboard, vài chục dòng. Rồi nó phình ra — thêm ô này, thêm nút kia, thêm logic nọ — tới lúc là một khối 300 dòng làm đủ thứ, không ai dám sửa. Cách chữa của mọi framework component (React, Vue, OWL) giống nhau: chia nhỏ thành sub-component. Bài slots tách phần giao diện; bài này tách phần dữ liệu và hành vi — mỗi con là một mảnh tự lo, giao tiếp với cha qua hai chiều rõ ràng.
Dữ liệu xuống bằng props, sự kiện lên bằng callback
Nguyên tắc vàng của luồng dữ liệu một chiều (đã gặp ở bài props): dữ liệu chảy XUỐNG từ cha tới con qua props; con không sửa props. Khi con cần báo điều gì cho cha (người dùng bấm nút, chọn dòng), nó gọi một callback mà cha truyền xuống — một hàm trong props. Cha giữ quyền quyết định, con chỉ "gõ cửa".
Mình tách ba ô số liệu của dashboard thành một sub-component TheCard:

Hình 1: Ba phần. Con TheCard: khai static props với kiểu cho từng prop (nhan: String, so: Number) — OWL kiểm props lúc chạy, sai kiểu là báo lỗi ngay. onChon: Function là callback. Template con: bấm nút gọi props.onChon(props.nhan) — con không tự xử lý, nó báo lên. Cha: khai static components = { TheCard }, viết hàm onChonCard nhận sự kiện, và truyền props xuống + callback lên qua <TheCard .../>.
Chạy thật: bấm con, cha nhận
Dashboard giờ chỉ lặp <TheCard/> ba lần, mỗi lần truyền props khác nhau. Bấm nút "Chọn" ở một ô:

Hình 2: Ba TheCard thật (4/385/1), mỗi cái nhận props riêng. Bấm "Chọn" ở ô giữa → con gọi props.onChon("Tổng điểm") → hàm onChonCard của cha chạy, bật toast "Bạn vừa chọn ô: Tổng điểm". Con không biết gì về notification; nó chỉ báo "tôi được chọn", cha quyết định làm gì. Đó là ranh giới trách nhiệm rõ ràng.
Vì sao bõ công tách
- Dễ đọc. Cha giờ là một vòng lặp ngắn; chi tiết vẽ một ô nằm gọn trong
TheCard. Đọc cha thấy bố cục, đọc con thấy một ô. - Tái dùng.
TheCarddùng được ở màn hình khác, không dính gì tới dashboard cụ thể — vì nó chỉ nhận props. - Dễ test và sửa. Lỗi ở cách vẽ ô? Sửa
TheCard, không đụng cha. Muốn thêm ô? Thêm một phần tử vàostate.items, không sửa template. - Ranh giới trách nhiệm. Con lo hiển thị và bắt tương tác; cha lo dữ liệu và quyết định. Không lẫn lộn.
Sub-component so với slots
Hai cách tách khác nhau, bổ sung nhau:
- Sub-component + props/callback (bài này): tách theo dữ liệu và hành vi. Con nhận dữ liệu cụ thể, báo sự kiện cụ thể. Dùng khi các mảnh có cùng cấu trúc, khác dữ liệu (danh sách ô, dòng bảng).
- Slots (bài trước): tách theo khung và nội dung. Con chừa chỗ, cha nhét giao diện tuỳ ý. Dùng khi cái khung cố định nhưng ruột mỗi nơi một khác.
Thực tế hay dùng cả hai: một sub-component nhận props và có slot.
Ba ý mang về
- Chia component lớn thành sub-component nhỏ, mỗi con một trách nhiệm — dễ đọc, tái dùng, test và sửa. Cha khai
static components = { Con }để dùng<Con/>. - Dữ liệu chảy XUỐNG bằng
props(khaistatic propsvới kiểu để OWL kiểm), sự kiện dội LÊN bằng callback prop (onXxx: Function, con gọiprops.onXxx(payload)). Con không sửa props, không tự quyết — nó báo, cha quyết. - Sub-component tách theo dữ liệu/hành vi; slots tách theo khung/nội dung — hai cách bổ sung nhau, hay dùng chung.
Trong TheCard ta vẽ HTML và để OWL lo DOM. Nhưng đôi khi bạn cần chạm thẳng vào một phần tử DOM thật — lấy chiều cao, focus một ô input, vẽ lên canvas. Phần sau nói về useRef: cách OWL cho bạn tham chiếu tới một node DOM thật một cách an toàn.