Skip to content
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

computed store properties #954

Merged
merged 19 commits into from
Nov 25, 2017
Merged

computed store properties #954

merged 19 commits into from
Nov 25, 2017

Conversation

Rich-Harris
Copy link
Member

@Rich-Harris Rich-Harris commented Nov 25, 2017

Adjunct to #951. This adds a compute method to Store:

import Store from 'svelte/store.js';

const store = new Store({ foo: 1 });

store.compute('bar', ['foo'], foo => foo * 2);
store.get('bar'); // 2
store.get(); // { foo: 1, bar: 2 }

Computed properties can depend on other computed properties, and be observed etc. Setting a computed property will cause an error to be thrown.

Might play around with the implementation a bit more but I think this is probably the right API. Thoughts?

@codecov-io
Copy link

codecov-io commented Nov 25, 2017

Codecov Report

Merging #954 into master will decrease coverage by 0.01%.
The diff coverage is 92%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #954      +/-   ##
==========================================
- Coverage   91.74%   91.73%   -0.02%     
==========================================
  Files         109      109              
  Lines        4010     4051      +41     
  Branches     1287     1300      +13     
==========================================
+ Hits         3679     3716      +37     
- Misses        148      150       +2     
- Partials      183      185       +2
Impacted Files Coverage Δ
src/generators/Generator.ts 93.87% <100%> (+0.03%) ⬆️
src/generators/dom/index.ts 95.4% <100%> (+0.16%) ⬆️
src/generators/server-side-rendering/index.ts 98% <100%> (+0.17%) ⬆️
src/validate/index.ts 86.66% <100%> (+0.3%) ⬆️
...rators/server-side-rendering/visitors/Component.ts 98.07% <100%> (+0.2%) ⬆️
src/validate/html/validateEventHandler.ts 86.95% <80%> (-1.94%) ⬇️
src/generators/dom/visitors/Element/addBindings.ts 96.02% <85%> (-1.72%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 14b27b7...d5d1ecc. Read the comment docs.

@Rich-Harris Rich-Harris mentioned this pull request Nov 25, 2017
3 tasks
@Rich-Harris
Copy link
Member Author

Improved the implementation a bit — no longer uses getters, but instead sorts computed properties topologically (like Svelte does at compile time) which a) avoids any unexpected object behaviour, and b) prevents unnecessary recomputation in some situations (because if computed property c depends on computed property b which depends on value a, we don't need to recompute c every time a changes — only if b changes).

Also added a combineStores function:

// NOTE — Store is no longer a default export
import { Store, combineStores } from 'svelte/store.js';

const a = new Store({
  x: 1,
  y: 2
});

a.compute('z', ['x', 'y'], (x, y) => x + y);

const b = new Store({
  x: 3,
  y: 4
});

b.compute('z', ['x', 'y'], (x, y) => x + y);

// optionally, provide an existing store as the second argument
const c = combineStores({ a, b });

c.compute('total', ['a', 'b'], (a, b) => a.z + b.z);

c.observe('total', total => {
  console.log(`total is ${total}`);
}); // total is 10

a.set({ x: 2 }); // total is 11
b.set({ x: 5, y: 6 }); // total is 15

@Rich-Harris
Copy link
Member Author

On reflection, combineStores may not be a great fit for Svelte — using the parent store's methods to update data on child stores causes problems with computed properties and bindings. So using it via inline event handlers and bind:thing=$x.y would cause unexpected behaviour. We could just say 'don't do that' in the documentation, but for now I reckon it's better to focus on the single-giant-global-store scenario.

If that proves to be a source of pain, we can solve it once we have a bit more data.

@Rich-Harris Rich-Harris merged commit a3b4eea into master Nov 25, 2017
@Rich-Harris Rich-Harris deleted the gh-930-computed branch November 25, 2017 22:18
@Conduitry
Copy link
Member

Was it intended for svelte/store.js to continue to export Store as a named export rather than as the default export? I'm not sure which would be preferable.

@Rich-Harris
Copy link
Member Author

It was, yeah — I can see us adding things like this in future, for example:

export function useLocalStorage(store, key) {
  const json = localStorage.getItem(key);
  if (json) {
    store.set(JSON.parse(json));
  }

  store.onchange(state => {
    localStorage.setItem(key, JSON.stringify(state));
  });
}

If we did a default export, it could make life harder in future (because of interop headaches that arise from modules with both default and named exports).

store.js Outdated

store._dirty[key] = true;
function visit(key) {
if (visited[key]) return;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is visited[key] set?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants