Skip to content

Store adds reset function that helps reset to initial state #1666

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 65 additions & 5 deletions dist/vuex.common.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* vuex v3.1.2
* (c) 2019 Evan You
* (c) 2020 Evan You
* @license MIT
*/
'use strict';
Expand Down Expand Up @@ -72,6 +72,47 @@ function devtoolPlugin (store) {
* @param {Function} f
* @return {*}
*/
function find (list, f) {
return list.filter(f)[0]
}

/**
* Deep copy the given object considering circular structure.
* This function caches all nested objects and its copies.
* If it detects circular structure, use cached copy to avoid infinite loop.
*
* @param {*} obj
* @param {Array<Object>} cache
* @return {*}
*/
function deepCopy (obj, cache) {
if ( cache === void 0 ) cache = [];

// just return if obj is immutable value
if (obj === null || typeof obj !== 'object') {
return obj
}

// if obj is hit, it is in circular structure
var hit = find(cache, function (c) { return c.original === obj; });
if (hit) {
return hit.copy
}

var copy = Array.isArray(obj) ? [] : {};
// put the copy into cache at first
// because we want to refer it in recursive deepCopy
cache.push({
original: obj,
copy: copy
});

Object.keys(obj).forEach(function (key) {
copy[key] = deepCopy(obj[key], cache);
});

return copy
}

/**
* forEach for object
Expand Down Expand Up @@ -109,6 +150,9 @@ var Module = function Module (rawModule, runtime) {

// Store the origin module's state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {};

// Preserving orignal module's state
this.originalState = deepCopy(this.state);
};

var prototypeAccessors = { namespaced: { configurable: true } };
Expand Down Expand Up @@ -394,7 +438,10 @@ Store.prototype.commit = function commit (_type, _payload, _options) {
handler(payload);
});
});
this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); });

this._subscribers
.slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
.forEach(function (sub) { return sub(mutation, this$1.state); });

if (
process.env.NODE_ENV !== 'production' &&
Expand Down Expand Up @@ -426,6 +473,7 @@ Store.prototype.dispatch = function dispatch (_type, _payload) {

try {
this._actionSubscribers
.slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
.filter(function (sub) { return sub.before; })
.forEach(function (sub) { return sub.before(action, this$1.state); });
} catch (e) {
Expand Down Expand Up @@ -525,6 +573,11 @@ Store.prototype._withCommit = function _withCommit (fn) {
this._committing = committing;
};

Store.prototype.reset = function reset () {
var originalState = getOriginalState(this._modules.root);
this.replaceState(originalState);
};

Object.defineProperties( Store.prototype, prototypeAccessors$1 );

function genericSubscribe (fn, subs) {
Expand Down Expand Up @@ -794,9 +847,7 @@ function enableStrictMode (store) {
}

function getNestedState (state, path) {
return path.length
? path.reduce(function (state, key) { return state[key]; }, state)
: state
return path.reduce(function (state, key) { return state[key]; }, state)
}

function unifyObjectStyle (type, payload, options) {
Expand All @@ -813,6 +864,15 @@ function unifyObjectStyle (type, payload, options) {
return { type: type, payload: payload, options: options }
}

function getOriginalState (module) {
var state = module.originalState || {};
module.forEachChild(function (child, key) {
state[key] = getOriginalState(child);
});

return state
}

function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
Expand Down
5 changes: 4 additions & 1 deletion src/module/module.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forEachValue } from '../util'
import { forEachValue, deepCopy } from '../util'

// Base data struct for store's module, package with some attribute and method
export default class Module {
Expand All @@ -12,6 +12,9 @@ export default class Module {

// Store the origin module's state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}

// Preserving orignal module's state
this.originalState = deepCopy(this.state)
}

get namespaced () {
Expand Down
14 changes: 14 additions & 0 deletions src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ export class Store {
fn()
this._committing = committing
}

reset () {
const originalState = getOriginalState(this._modules.root)
this.replaceState(originalState)
}
}

function genericSubscribe (fn, subs) {
Expand Down Expand Up @@ -510,6 +515,15 @@ function unifyObjectStyle (type, payload, options) {
return { type, payload, options }
}

function getOriginalState (module) {
const state = module.originalState || {}
module.forEachChild((child, key) => {
state[key] = getOriginalState(child)
})

return state
}

export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
Expand Down
48 changes: 48 additions & 0 deletions test/unit/store.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,5 +434,53 @@ describe('Store', () => {
})
})
})

it('reset: Store resets to initial', done => {
const store = new Vuex.Store({
state: {
count: 0,
arr: [],
obj: {
name: 0
}
},
mutations: {
[TEST]: state => {
state.count++
state.arr.push(1)
state.obj.name = 1
}
},
modules: {
sub: {
namespaced: true,
state: {
count: 0
},
mutations: {
[TEST]: state => state.count++
}
}
}
})
store.commit(TEST)
store.commit('sub/' + TEST)

Vue.nextTick(() => {
expect(store.state.count).toBe(1)
expect(store.state.arr.length).toBe(1)
expect(store.state.obj.name).toBe(1)
expect(store.state.sub.count).toBe(1)

store.reset()
Vue.nextTick(() => {
expect(store.state.count).toBe(0)
expect(store.state.arr.length).toBe(0)
expect(store.state.obj.name).toBe(0)
expect(store.state.sub.count).toBe(0)
done()
})
})
})
}
})