How to reset to initial state in VueJS

How do we reset to the initial state in VueJS 3? Sometimes we have a component that has many states that need to be reset to initial values. I stumbled upon this problem today and found it interesting. Consider this simple example below.

JSXApp.vue
1<script>
2export default {
3  data: () => ({
4  items: [], deep: { items: [] }, counter: 0}),
5  methods: {
6   resetState() {
7    // 
8   },
9  },
10}
11</script>
12
13<template>
14  <button @click="items.push(items.length + 1); deep.items.push(items.length); counter++;">
15    Add item
16  </button>
17  <button @click="resetState">
18    Reset State
19  </button>
20  <hr />
21  <pre>{{ $data }}</pre>
22</template>

In this case, you can do it manually like this

JSXApp.vue
1...
2methods: {
3   resetState() {
4      this.$data.items = [];
5      this.$data.deep = { items: [] };
6      this.$data.counter=0;
7   }
8}
9...

But what if we retrieve the initial state from a function? Can we still do it like this.$data = this.getInitialState()? For instance,

JSXApp.vue
1<script>
2const getInitialState = () => ({ items: [], deep: { items: [] }, counter: 0});
3
4export default {
5  data: getInitialState,
6  methods: {
7    resetState() {
8      this.$data = getInitialState();
9    }
10  }
11}
12</script>
13
14<template>
15  ...
16</template>

No, we will this error - proxy set handler returned false for property '"$data"'. It is not possible due to data being read-only and can not be overwritten. We can instead do it like this

JSXApp.vue
1<script>
2const getInitialState = () => ({ items: [], deep: { items: [] }, counter: 0});
3
4export default {
5  data: getInitialState,
6  methods: {
7    resetState() {
8      Object.assign(this.$data, getInitialState()});
9    }
10  }
11}
12</script>
13
14<template>
15  ...
16</template>

Object.assign will copy all values returned from getInitialState into the data object. And if we don't want to overwrite all states e.g. counter, we can do it like this

JSXApp.vue
1<script>
2const getInitialState = () => ({ items: [], deep: { items: [] }, counter: 0});
3
4export default {
5  data: getInitialState,
6  methods: {
7    resetState() {
8      const counter = this.$data.counter;
9      Object.assign(this.$data, {...getInitialState(), counter});
10    }
11  }
12}
13</script>
14
15<template>
16  <button @click="items.push(items.length + 1); deep.items.push(items.length); counter++;">
17    Add item
18  </button>
19  <button @click="resetState">
20    Reset State
21  </button>
22  <hr />
23  <pre>{{ $data }}</pre>
24</template>
Back to blog
Discuss on TwitterTweet about this post
  • Email
  • GitHub
  • Twitter
  • Codepen
  • LinkedIn
  • GitLab