Skip to content

Commit

Permalink
Merge pull request #1395 from sveltejs/gh-1327
Browse files Browse the repository at this point in the history
Update store state when new computed properties are added
  • Loading branch information
Rich-Harris authored May 3, 2018
2 parents ea95ae7 + c8d55aa commit bea1265
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 68 deletions.
143 changes: 75 additions & 68 deletions store.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ function Store(state, options) {
}

assign(Store.prototype, {
_add: function(component, props) {
_add(component, props) {
this._dependents.push({
component: component,
props: props
});
},

_init: function(props) {
var state = {};
for (var i = 0; i < props.length; i += 1) {
var prop = props[i];
_init(props) {
const state = {};
for (let i = 0; i < props.length; i += 1) {
const prop = props[i];
state['$' + prop] = this._state[prop];
}
return state;
},

_remove: function(component) {
var i = this._dependents.length;
_remove(component) {
let i = this._dependents.length;
while (i--) {
if (this._dependents[i].component === component) {
this._dependents.splice(i, 1);
Expand All @@ -46,14 +46,52 @@ assign(Store.prototype, {
}
},

_sortComputedProperties: function() {
var computed = this._computed;
var sorted = this._sortedComputedProperties = [];
var visited = blankObject();
var currentKey;
_set(newState, changed) {
const previous = this._state;
this._state = assign(assign({}, previous), newState);

for (let i = 0; i < this._sortedComputedProperties.length; i += 1) {
this._sortedComputedProperties[i].update(this._state, changed);
}

this.fire('state', {
changed,
previous,
current: this._state
});

const dependents = this._dependents.slice(); // guard against mutations
for (let i = 0; i < dependents.length; i += 1) {
const dependent = dependents[i];
const componentState = {};
dirty = false;

for (let j = 0; j < dependent.props.length; j += 1) {
const prop = dependent.props[j];
if (prop in changed) {
componentState['$' + prop] = this._state[prop];
dirty = true;
}
}

if (dirty) dependent.component.set(componentState);
}

this.fire('update', {
changed,
previous,
current: this._state
});
},

_sortComputedProperties() {
const computed = this._computed;
const sorted = this._sortedComputedProperties = [];
const visited = blankObject();
let currentKey;

function visit(key) {
var c = computed[key];
const c = computed[key];

if (c) {
c.deps.forEach(dep => {
Expand All @@ -71,26 +109,25 @@ assign(Store.prototype, {
}
}

for (var key in this._computed) {
for (const key in this._computed) {
visit(currentKey = key);
}
},

compute: function(key, deps, fn) {
var store = this;
var value;
compute(key, deps, fn) {
let value;

var c = {
deps: deps,
update: function(state, changed, dirty) {
var values = deps.map(function(dep) {
const c = {
deps,
update: (state, changed, dirty) => {
const values = deps.map(dep => {
if (dep in changed) dirty = true;
return state[dep];
});

if (dirty) {
var newValue = fn.apply(null, values);
if (store._differs(newValue, value)) {
const newValue = fn.apply(null, values);
if (this._differs(newValue, value)) {
value = newValue;
changed[key] = true;
state[key] = value;
Expand All @@ -99,63 +136,33 @@ assign(Store.prototype, {
}
};

c.update(this._state, {}, true);

this._computed[key] = c;
this._sortComputedProperties();

const state = assign({}, this._state);
const changed = {};
c.update(state, changed, true);
this._set(state, changed);
},

fire: fire,
fire,

get: get,
get,

on: on,
on,

set: function(newState) {
var oldState = this._state,
changed = this._changed = {},
dirty = false;
set(newState) {
const oldState = this._state;
const changed = this._changed = {};
let dirty = false;

for (var key in newState) {
if (this._computed[key]) throw new Error("'" + key + "' is a read-only property");
for (const 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;
}
if (!dirty) return;

this._state = assign(assign({}, oldState), newState);

for (var i = 0; i < this._sortedComputedProperties.length; i += 1) {
this._sortedComputedProperties[i].update(this._state, changed);
}

this.fire('state', {
changed: changed,
current: this._state,
previous: oldState
});

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);
}

this.fire('update', {
changed: changed,
current: this._state,
previous: oldState
});
this._set(newState, changed);
}
});

Expand Down
11 changes: 11 additions & 0 deletions test/runtime/samples/store-computed-oncreate/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Store } from '../../../../store.js';

export default {
'skip-ssr': true,

store: new Store(),

html: `
<h1>Hello Brian!</h1>
`
};
10 changes: 10 additions & 0 deletions test/runtime/samples/store-computed-oncreate/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<h1>Hello {$name}!</h1>

<script>
export default {
oncreate() {
this.store.set({ user: { name: 'Brian' } });
this.store.compute('name', ['user'], user => user && user.name);
}
};
</script>

0 comments on commit bea1265

Please sign in to comment.