0
0
mirror of https://github.com/sveltejs/svelte.git synced 2024-11-25 09:09:35 +01:00
svelte/store.js

163 lines
3.3 KiB
JavaScript
Raw Normal View History

2017-11-24 18:50:12 +01:00
import {
assign,
blankObject,
_differs,
_differsImmutable,
2017-11-24 18:50:12 +01:00
get,
2018-04-15 19:09:59 +02:00
on,
fire
2017-11-24 18:50:12 +01:00
} from './shared.js';
function Store(state, options) {
2018-04-15 19:09:59 +02:00
this._handlers = {};
2017-11-24 18:50:12 +01:00
this._dependents = [];
2017-11-25 18:07:28 +01:00
this._computed = blankObject();
this._sortedComputedProperties = [];
this._state = assign({}, state);
this._differs = options && options.immutable ? _differsImmutable : _differs;
2017-11-24 18:50:12 +01:00
}
assign(Store.prototype, {
_add: function(component, props) {
this._dependents.push({
component: component,
props: props
});
},
2017-11-24 19:56:32 +01:00
_init: function(props) {
var state = {};
2017-11-25 20:09:41 +01:00
for (var i = 0; i < props.length; i += 1) {
2017-11-24 19:56:32 +01:00
var prop = props[i];
state['$' + prop] = this._state[prop];
}
return state;
},
2017-11-24 18:50:12 +01:00
_remove: function(component) {
2017-11-25 20:09:41 +01:00
var i = this._dependents.length;
2017-11-24 18:50:12 +01:00
while (i--) {
if (this._dependents[i].component === component) {
this._dependents.splice(i, 1);
return;
}
}
},
2017-11-25 20:09:41 +01:00
_sortComputedProperties: function() {
var computed = this._computed;
var sorted = this._sortedComputedProperties = [];
var visited = blankObject();
var cycles = blankObject();
2017-11-25 18:07:28 +01:00
2018-05-02 04:27:18 +02:00
function visit(key) {
if (visited[key]) return;
2018-05-02 04:27:18 +02:00
visited[key] = true;
var c = computed[key];
2017-11-25 18:07:28 +01:00
if (c) {
if (!cycles[key]) cycles[key] = blankObject();
2018-05-02 04:27:18 +02:00
c.deps.forEach(dep => {
if (cycles[dep] && cycles[dep][key]) {
2018-05-02 04:27:18 +02:00
throw new Error(`Cyclical dependency detected between ${dep} <-> ${key}`);
}
cycles[key][dep] = true;
2018-05-02 04:27:18 +02:00
visit(dep);
});
sorted.push(c);
}
2017-11-25 18:07:28 +01:00
}
for (var key in this._computed) {
2018-05-02 04:27:18 +02:00
visit(key);
}
},
2017-11-25 18:07:28 +01:00
compute: function(key, deps, fn) {
var store = this;
var value;
var c = {
deps: deps,
update: function(state, changed, dirty) {
var values = deps.map(function(dep) {
if (dep in changed) dirty = true;
return state[dep];
});
2017-11-25 18:07:28 +01:00
if (dirty) {
var newValue = fn.apply(null, values);
if (store._differs(newValue, value)) {
2017-11-25 18:07:28 +01:00
value = newValue;
changed[key] = true;
state[key] = value;
2017-11-25 18:07:28 +01:00
}
}
}
};
c.update(this._state, {}, true);
this._computed[key] = c;
this._sortComputedProperties();
2017-11-25 18:07:28 +01:00
},
2018-04-15 19:09:59 +02:00
fire: fire,
2017-11-25 20:09:41 +01:00
get: get,
2018-04-15 19:09:59 +02:00
on: on,
2017-11-24 18:50:12 +01:00
set: function(newState) {
var oldState = this._state,
2017-11-25 18:07:28 +01:00
changed = this._changed = {},
2017-11-24 18:50:12 +01:00
dirty = false;
for (var key in newState) {
if (this._computed[key]) throw new Error("'" + key + "' is a read-only property");
if (this._differs(newState[key], oldState[key])) changed[key] = dirty = true;
2017-11-24 18:50:12 +01:00
}
if (!dirty) return;
2018-03-27 22:21:29 +02:00
this._state = assign(assign({}, oldState), newState);
2017-11-25 18:07:28 +01:00
for (var i = 0; i < this._sortedComputedProperties.length; i += 1) {
this._sortedComputedProperties[i].update(this._state, changed);
}
2017-11-24 18:50:12 +01:00
2018-04-15 19:09:59 +02:00
this.fire('state', {
changed: changed,
current: this._state,
previous: oldState
});
2017-11-24 18:50:12 +01:00
var dependents = this._dependents.slice(); // guard against mutations
for (var i = 0; i < dependents.length; i += 1) {
var dependent = dependents[i];
var componentState = {};
dirty = false;
for (var j = 0; j < dependent.props.length; j += 1) {
var prop = dependent.props[j];
if (prop in changed) {
componentState['$' + prop] = this._state[prop];
dirty = true;
}
}
if (dirty) dependent.component.set(componentState);
}
2018-04-15 19:09:59 +02:00
this.fire('update', {
changed: changed,
current: this._state,
previous: oldState
});
2017-11-24 18:50:12 +01:00
}
});
export { Store };