Vue.js 重設或還原 data 初始值的小技巧

前言

通常來講,我們在開發時往往會很需要還原初始值,因此這一篇就來分享一下小技巧,而這個小技巧基本上不論是 Vue2 還是 Vue3 都是通用的。

情境

我們其實很常需要與遠端伺服器做 AJAX 溝通,那麼當使用者溝通完畢後,總是會有一種狀況存在,就是使用者輸入的原始資料依然保留在 Vue Data 中,這時候可能會有一些很麻煩的問題發生,所以我這邊寫了一段程式碼模擬了使用者輸入之後點連結觸發 AJAX 的行為(並不是真的觸發,只是用 setTimeout 語法模擬而已)。

1
2
3
4
5
6
7
<div id="app">
請輸入你的姓名:
<input type="text" v-model="myName">
<div>我的名字是:{{ myName }}</div>
<br>
<a href="#" @click.prevent="ajax">點我觸發 AJAX</a>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vue.createApp({
data() {
return {
myName: ''
}
},
methods: {
ajax() {
setTimeout(() => {
console.log('新增成功!');
console.log('但是原始資料依然存在:', this.myName);
}, 1500);
}
}
}).mount('#app');

你可以試著點以下 Codepen 試試看

Reset Options API Data

那麼為了達到這個需求,通常我們可能這樣做,在 AJAX 之後重新賦予空值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vue.createApp({
data() {
return {
myName: ''
}
},
methods: {
ajax() {
setTimeout(() => {
console.log('新增成功!');
this.myName = '';
}, 1500);
}
}
}).mount('#app');

但這種做法其實是會有一些問題存在,當如果你是一個物件時,你就必須重新寫一樣的物件屬性,當有 10 個屬性你就要寫 10 次,其實這樣格外麻煩且可能維護上會有一些問題。

那該如何解決才會比較好呢?其實非常簡單,你只需要這樣寫就好了

1
this.$options.data()

在 Vue 官方文件中其實有提到這個 物件 屬性,以下擷取官方文件說明:

用于当前组件实例的初始化选项。

$options

看起來文謅謅吧?簡單來講就是…

當你 Vue 準備完畢時,它會將你初始化的 data 資料拷貝一份到 this.$options 底下,data 本身是一個函式,所以你必須使用呼叫的方式,因此你就可以將上方改寫成以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Vue.createApp({
data() {
return {
myName: ''
}
},
methods: {
ajax() {
console.log(this);
setTimeout(() => {
console.log('新增成功!');
this.myName = this.$options.data().myName
console.log('資料變成初始了:', this.myName);
}, 1500);
}
}
}).mount('#app');

這樣子在做還原初始值是一個比較安全且保險的方式,畢竟你在第一次渲染時都會盡可能的定義初始值,那麼要還原初始值的話,反而會建議使用 this.$options.data() 會較穩定(避免你粗手指漏寫)

雖然上面是使用 Vue3 去做範例,但是 Vue2 本身就是 Options API 因此其實兩者都是通用的。

Reset Composition API Data

那麼問題來了,因為 Vue3 本身是支援 Options API,所以可以透過 this 呼叫 $options,但是在 Vue3 的 Composition API 中並沒有辦法使用 this,那這樣子該怎麼辦呢?

剛好在官方 issues 中就有人提出解決方式

因此我們就知道可以透過 Object.assign 來做到類似重設的效果,透過上面討論的話我們可以改成以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Vue.createApp({
setup() {
const initialData = {
myName: '',
}
const data = Vue.reactive({ ...initialData });

const ajax = () => {
setTimeout(() => {
console.log('新增成功!');
Object.assign(data, initialData);
console.log('資料變成初始了:', data.myName);
}, 1500);
}

return {
data,
ajax
}
}
}).mount('#app');

See the Pen Vue3 reactive toRef by Ray (@hsiangfeng) on CodePen.

而另一種寫法則是像這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Vue.createApp({
setup() {
const initialData = () => {
return {
myName: '',
}
}
const data = Vue.reactive(initialData());

const ajax = () => {
setTimeout(() => {
console.log('新增成功!');
Object.assign(data, initialData());
console.log('資料變成初始了:', data.myName);
}, 1500);
}

return {
data,
ajax
}
}
}).mount('#app');

那這時候你可能會問 ref 呢?通常來講 ref 並不會拿來一次放許多物件屬性,因此比較不會遇到需要 reset 的問題,如果真的需要 reset 也是直接重新賦予值就好了,畢竟 ref 就只是一個單一型別的值。