effect() sinh ra để đồng bộ với thế giới bên ngoài Angular: ghi localStorage, log/analytics, vẽ lên canvas, gọi API của thư viện DOM. Nó không phải công cụ để suy ra state.
Ba trường hợp nên tránh:
// 1. deriving state → use computed
effect(() => { this.total.set(this.qty() * this.price()) }) // avoid
readonly total = computed(() => this.qty() * this.price()) // correct
// 2. resetting local state when an input changes → use linkedSignal
readonly selected = linkedSignal(() => this.options()[0])
// 3. propagating between signals → risk of an update loopVì sao tránh: computed được cache và lazy (chỉ tính khi có ai đọc), còn effect luôn chạy, dễ tạo chuỗi cập nhật khó lần và làm state có nhiều nguồn sự thật. Ghi vào signal trong effect còn có thể gây vòng lặp — Angular mặc định báo lỗi khi effect ghi vào signal mà chính nó đọc.
Khi thực sự cần effect:
- Effect tạo trong injection context tự huỷ theo component; ngoài context phải truyền { injector } hoặc tự destroy().
- Dùng onCleanup để dọn tài nguyên trước lần chạy kế tiếp.
- Muốn giới hạn dependency thì bọc phần đọc không nên theo dõi bằng untracked().
Quy tắc ngắn: suy ra giá trị → computed; state phụ thuộc input nhưng vẫn ghi đè được → linkedSignal; dữ liệu async → resource/toSignal; chỉ side effect ra ngoài mới dùng effect.