Reactive Forms 與 LocalStorage 整合
Reactive Forms 與 Template-driven Forms 在與 LocalStorage 整合時有一些關鍵差異。
時機差異
在使用 Reactive Forms 時,不需要等到 afterNextRender
才與表單互動,可以直接在 ngOnInit
生命週期鉤子中進行:
ngOnInit(): void {
// 從 localStorage 讀取並設置表單值
const savedForm = window.localStorage.getItem('saved-login-form');
if (savedForm) {
try {
const loadedForm = JSON.parse(savedForm);
this.loginForm.patchValue({
email: loadedForm.email,
});
} catch (error) {
console.error('Error parsing saved form data', error);
}
}
// 監聽表單變化並保存到 localStorage
const subscription = this.loginForm.valueChanges
.pipe(debounceTime(500))
.subscribe({
next: (value) => {
window.localStorage.setItem(
'saved-login-form',
JSON.stringify({ email: value.email })
);
},
});
// 組件銷毀時取消訂閱
this.destroyRef.onDestroy(() => {
subscription.unsubscribe();
});
}
這是因為 Reactive Forms 不依賴範本初始化,表單模型完全在 TypeScript 中定義和控制。
使用 patchValue 更新表單
patchValue
方法允許我們只更新表單的部分控制項,而不需要提供所有控制項的值:
this.loginForm.patchValue({
email: loadedForm.email,
// 不需要包含 password 或其他控制項
});
相比之下,setValue
方法要求提供所有控制項的值,否則會報錯。
更優雅的方法:初始化時設定預設值
由於 Reactive Forms 的特性,我們可以採用更優雅的方式,直接在 FormControl 初始化時設定從 localStorage 讀取的值:
// 在元件類別外部執行,只會在首次載入模組時執行一次
let initialEmailValue = '';
const savedForm = window.localStorage.getItem('saved-login-form');
if (savedForm) {
try {
const loadedForm = JSON.parse(savedForm);
initialEmailValue = loadedForm.email;
} catch (error) {
console.error('Error parsing saved form data', error);
}
}
@Component({...})
export class LoginComponent {
// 直接在建立 FormControl 時使用初始值
loginForm = new FormGroup({
email: new FormControl(initialEmailValue, {
validators: [Validators.required, Validators.email],
asyncValidators: [emailIsUnique],
}),
password: new FormControl('', [...])
});
// 仍然需要監聽變化來保存到 localStorage
ngOnInit(): void {
const subscription = this.loginForm.valueChanges
.pipe(debounceTime(500))
.subscribe({...});
this.destroyRef.onDestroy(() => {
subscription.unsubscribe();
});
}
}
這種方法的好處是不需要在初始化後再次更新表單值,避免了不必要的狀態變化。
兩種方法比較
ngOnInit 中使用 patchValue:
優點:集中在生命週期鉤子中處理,邏輯清晰
缺點:表單初始化後又立即更新,可能導致狀態變化
FormControl 初始化時設置:
優點:更加優雅,避免不必要的狀態變化
缺點:邏輯分散在元件外部,可能對某些開發者來說不直觀
Last updated